blob: a0dcd54301ad839d537bb40dee91ea02aca454bb [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
Myung Baeafc474a2024-10-09 00:53:29 -07001552 if (!json_util::readJsonObject( //
1553 *obj, asyncResp->res, //
1554 "Address", address, //
1555 "Gateway", gateway, //
1556 "SubnetMask", subnetMask //
1557 ))
Ed Tanousbf648f72021-06-03 15:00:14 -07001558 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001559 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001560 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001561 return;
1562 }
1563
1564 // Find the address/subnet/gateway values. Any values that are
1565 // not explicitly provided are assumed to be unmodified from the
1566 // current state of the interface. Merge existing state into the
1567 // current request.
Ed Tanousbf648f72021-06-03 15:00:14 -07001568 if (address)
1569 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001570 if (!ip_util::ipv4VerifyIpAndGetBitcount(*address))
Ed Tanousbf648f72021-06-03 15:00:14 -07001571 {
1572 messages::propertyValueFormatError(asyncResp->res, *address,
1573 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001574 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001575 }
1576 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001577 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001578 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001579 address = (nicIpEntry->address);
Ed Tanousbf648f72021-06-03 15:00:14 -07001580 }
1581 else
1582 {
1583 messages::propertyMissing(asyncResp->res,
1584 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001585 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001586 }
1587
Ed Tanouse01d0c32023-06-30 13:21:32 -07001588 uint8_t prefixLength = 0;
Ed Tanousbf648f72021-06-03 15:00:14 -07001589 if (subnetMask)
1590 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001591 if (!ip_util::ipv4VerifyIpAndGetBitcount(*subnetMask,
1592 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001593 {
1594 messages::propertyValueFormatError(
1595 asyncResp->res, *subnetMask,
1596 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001597 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001598 }
1599 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001600 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001601 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001602 if (!ip_util::ipv4VerifyIpAndGetBitcount(nicIpEntry->netmask,
1603 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001604 {
1605 messages::propertyValueFormatError(
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001606 asyncResp->res, nicIpEntry->netmask,
Ed Tanousbf648f72021-06-03 15:00:14 -07001607 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001608 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001609 }
1610 }
1611 else
1612 {
1613 messages::propertyMissing(asyncResp->res,
1614 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001615 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001616 }
1617
1618 if (gateway)
1619 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001620 if (!ip_util::ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001621 {
1622 messages::propertyValueFormatError(asyncResp->res, *gateway,
1623 pathString + "/Gateway");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001624 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001625 }
1626 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001627 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001628 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001629 gateway = nicIpEntry->gateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001630 }
1631 else
1632 {
1633 messages::propertyMissing(asyncResp->res,
1634 pathString + "/Gateway");
Ed Tanousbf648f72021-06-03 15:00:14 -07001635 return;
1636 }
1637
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001638 if (gatewayValueAssigned)
1639 {
1640 if (activeGateway != gateway)
1641 {
1642 // A NIC can only have a single active gateway value.
1643 // If any gateway in the array of static addresses
1644 // mismatch the PATCH is in error.
1645 std::string arg1 = pathString + "/Gateway";
1646 std::string arg2 = activePath + "/Gateway";
1647 messages::propertyValueConflict(asyncResp->res, arg1, arg2);
1648 return;
1649 }
1650 }
1651 else
1652 {
1653 // Capture the very first gateway value from the incoming
1654 // JSON record and use it at the default gateway.
1655 updateIPv4DefaultGateway(ifaceId, *gateway, asyncResp);
1656 activeGateway = *gateway;
1657 activePath = pathString;
1658 gatewayValueAssigned = true;
1659 }
1660
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001661 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001662 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001663 deleteAndCreateIPAddress(IpVersion::IpV4, ifaceId,
Ed Tanous77eb0152023-09-06 10:19:18 -07001664 nicIpEntry->id, prefixLength, *address,
1665 *gateway, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001666 nicIpEntry =
1667 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001668 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001669 }
1670 else
1671 {
1672 createIPv4(ifaceId, prefixLength, *gateway, *address,
1673 asyncResp);
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001674 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001675 }
1676 entryIdx++;
1677 }
1678 else
1679 {
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001680 // Received {}, do not modify this address
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001681 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001682 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001683 nicIpEntry =
1684 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001685 preserveGateway = true;
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001686 entryIdx++;
Ed Tanousbf648f72021-06-03 15:00:14 -07001687 }
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001688 else
1689 {
1690 // Requested a DO NOT MODIFY action on an entry not assigned
1691 // to the NIC
1692 messages::propertyValueFormatError(asyncResp->res, *obj,
1693 pathString);
1694 return;
1695 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001696 }
1697 }
1698}
1699
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001700inline void handleStaticNameServersPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001701 const std::string& ifaceId,
1702 const std::vector<std::string>& updatedStaticNameServers,
1703 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1704{
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001705 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301706 asyncResp, "StaticNameServers", "xyz.openbmc_project.Network",
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001707 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1708 ifaceId,
George Liu9ae226f2023-06-21 17:56:46 +08001709 "xyz.openbmc_project.Network.EthernetInterface", "StaticNameServers",
Ginu Georgee93abac2024-06-14 17:35:27 +05301710 updatedStaticNameServers);
Ed Tanousbf648f72021-06-03 15:00:14 -07001711}
1712
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001713inline void handleIPv6StaticAddressesPatch(
Ed Tanous3dfed532024-03-06 14:41:27 -08001714 const std::string& ifaceId,
1715 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Ed Tanous77179532023-02-28 10:45:28 -08001716 const std::vector<IPv6AddressData>& ipv6Data,
Ed Tanousbf648f72021-06-03 15:00:14 -07001717 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1718{
Ed Tanousbf648f72021-06-03 15:00:14 -07001719 size_t entryIdx = 1;
Ed Tanous77179532023-02-28 10:45:28 -08001720 std::vector<IPv6AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001721 getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ed Tanous3dfed532024-03-06 14:41:27 -08001722 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1723 input)
Ed Tanousbf648f72021-06-03 15:00:14 -07001724 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001725 std::string pathString =
1726 "IPv6StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001727 nlohmann::json::object_t* obj =
1728 std::get_if<nlohmann::json::object_t>(&thisJson);
1729 if (obj != nullptr && !obj->empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001730 {
1731 std::optional<std::string> address;
1732 std::optional<uint8_t> prefixLength;
Ed Tanous3dfed532024-03-06 14:41:27 -08001733 nlohmann::json::object_t thisJsonCopy = *obj;
Myung Baeafc474a2024-10-09 00:53:29 -07001734 if (!json_util::readJsonObject( //
1735 thisJsonCopy, asyncResp->res, //
1736 "Address", address, //
1737 "PrefixLength", prefixLength //
1738 ))
Ed Tanousbf648f72021-06-03 15:00:14 -07001739 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001740 messages::propertyValueFormatError(asyncResp->res, thisJsonCopy,
Ed Tanousf818b042022-06-27 13:17:35 -07001741 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001742 return;
1743 }
1744
Ed Tanousbf648f72021-06-03 15:00:14 -07001745 // Find the address and prefixLength values. Any values that are
1746 // not explicitly provided are assumed to be unmodified from the
1747 // current state of the interface. Merge existing state into the
1748 // current request.
Ed Tanousd547d8d2024-03-16 18:04:41 -07001749 if (!address)
Ed Tanousbf648f72021-06-03 15:00:14 -07001750 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001751 if (nicIpEntry == ipv6Data.end())
1752 {
1753 messages::propertyMissing(asyncResp->res,
1754 pathString + "/Address");
1755 return;
1756 }
1757 address = nicIpEntry->address;
Ed Tanousbf648f72021-06-03 15:00:14 -07001758 }
1759
Ed Tanousd547d8d2024-03-16 18:04:41 -07001760 if (!prefixLength)
Ed Tanousbf648f72021-06-03 15:00:14 -07001761 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001762 if (nicIpEntry == ipv6Data.end())
1763 {
1764 messages::propertyMissing(asyncResp->res,
1765 pathString + "/PrefixLength");
1766 return;
1767 }
1768 prefixLength = nicIpEntry->prefixLength;
Ed Tanousbf648f72021-06-03 15:00:14 -07001769 }
1770
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001771 if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001772 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001773 deleteAndCreateIPAddress(IpVersion::IpV6, ifaceId,
Ed Tanousd547d8d2024-03-16 18:04:41 -07001774 nicIpEntry->id, *prefixLength,
1775 *address, "", asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001776 nicIpEntry =
1777 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001778 }
1779 else
1780 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001781 createIPv6(ifaceId, *prefixLength, *address, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001782 }
1783 entryIdx++;
1784 }
1785 else
1786 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001787 if (nicIpEntry == ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001788 {
1789 // Requesting a DELETE/DO NOT MODIFY action for an item
1790 // that isn't present on the eth(n) interface. Input JSON is
1791 // in error, so bail out.
Ed Tanous3dfed532024-03-06 14:41:27 -08001792 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001793 {
1794 messages::resourceCannotBeDeleted(asyncResp->res);
1795 return;
1796 }
Ed Tanous3dfed532024-03-06 14:41:27 -08001797 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001798 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001799 return;
1800 }
1801
Ed Tanous3dfed532024-03-06 14:41:27 -08001802 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001803 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001804 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001805 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001806 if (nicIpEntry != ipv6Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001807 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001808 nicIpEntry =
1809 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001810 }
1811 entryIdx++;
1812 }
1813 }
1814}
1815
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001816inline std::string extractParentInterfaceName(const std::string& ifaceId)
1817{
1818 std::size_t pos = ifaceId.find('_');
1819 return ifaceId.substr(0, pos);
1820}
1821
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001822inline void parseInterfaceData(
1823 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1824 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1825 const std::vector<IPv4AddressData>& ipv4Data,
1826 const std::vector<IPv6AddressData>& ipv6Data,
1827 const std::vector<StaticGatewayData>& ipv6GatewayData)
Ed Tanousbf648f72021-06-03 15:00:14 -07001828{
Ed Tanousbf648f72021-06-03 15:00:14 -07001829 nlohmann::json& jsonResponse = asyncResp->res.jsonValue;
1830 jsonResponse["Id"] = ifaceId;
Ed Tanous253f11b2024-05-16 09:38:31 -07001831 jsonResponse["@odata.id"] =
1832 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
1833 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceId);
Ed Tanousbf648f72021-06-03 15:00:14 -07001834 jsonResponse["InterfaceEnabled"] = ethData.nicEnabled;
1835
Ed Tanousbf648f72021-06-03 15:00:14 -07001836 if (ethData.nicEnabled)
1837 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001838 jsonResponse["LinkStatus"] =
1839 ethData.linkUp ? ethernet_interface::LinkStatus::LinkUp
1840 : ethernet_interface::LinkStatus::LinkDown;
1841 jsonResponse["Status"]["State"] = resource::State::Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001842 }
1843 else
1844 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001845 jsonResponse["LinkStatus"] = ethernet_interface::LinkStatus::NoLink;
1846 jsonResponse["Status"]["State"] = resource::State::Disabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001847 }
1848
Ed Tanousbf648f72021-06-03 15:00:14 -07001849 jsonResponse["SpeedMbps"] = ethData.speed;
Tejas Patil35fb5312021-09-20 15:35:20 +05301850 jsonResponse["MTUSize"] = ethData.mtuSize;
Asmitha Karunanithi4652c642024-07-30 11:35:53 -05001851 if (ethData.macAddress)
1852 {
1853 jsonResponse["MACAddress"] = *ethData.macAddress;
1854 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001855 jsonResponse["DHCPv4"]["DHCPEnabled"] =
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001856 translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
Jishnu CMe4588152023-05-11 00:04:40 -05001857 jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.ntpv4Enabled;
1858 jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.dnsv4Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001859 jsonResponse["DHCPv4"]["UseDomainName"] = ethData.domainv4Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001860 jsonResponse["DHCPv6"]["OperatingMode"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001861 translateDhcpEnabledToBool(ethData.dhcpEnabled, false)
1862 ? "Enabled"
1863 : "Disabled";
Jishnu CMe4588152023-05-11 00:04:40 -05001864 jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.ntpv6Enabled;
1865 jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.dnsv6Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001866 jsonResponse["DHCPv6"]["UseDomainName"] = ethData.domainv6Enabled;
Ravi Tejab10d8db2022-05-24 09:04:12 -05001867 jsonResponse["StatelessAddressAutoConfig"]["IPv6AutoConfigEnabled"] =
1868 ethData.ipv6AcceptRa;
Ed Tanousbf648f72021-06-03 15:00:14 -07001869
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001870 if (!ethData.hostName.empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001871 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001872 jsonResponse["HostName"] = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001873
1874 // When domain name is empty then it means, that it is a network
1875 // without domain names, and the host name itself must be treated as
1876 // FQDN
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001877 std::string fqdn = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001878 if (!ethData.domainnames.empty())
1879 {
1880 fqdn += "." + ethData.domainnames[0];
1881 }
1882 jsonResponse["FQDN"] = fqdn;
1883 }
1884
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001885 if (ethData.vlanId)
1886 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001887 jsonResponse["EthernetInterfaceType"] =
1888 ethernet_interface::EthernetDeviceType::Virtual;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001889 jsonResponse["VLAN"]["VLANEnable"] = true;
1890 jsonResponse["VLAN"]["VLANId"] = *ethData.vlanId;
1891 jsonResponse["VLAN"]["Tagged"] = true;
1892
1893 nlohmann::json::array_t relatedInterfaces;
1894 nlohmann::json& parentInterface = relatedInterfaces.emplace_back();
1895 parentInterface["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001896 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces",
1897 BMCWEB_REDFISH_MANAGER_URI_NAME,
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001898 extractParentInterfaceName(ifaceId));
1899 jsonResponse["Links"]["RelatedInterfaces"] =
1900 std::move(relatedInterfaces);
1901 }
1902 else
1903 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001904 jsonResponse["EthernetInterfaceType"] =
1905 ethernet_interface::EthernetDeviceType::Physical;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001906 }
1907
Ed Tanousbf648f72021-06-03 15:00:14 -07001908 jsonResponse["NameServers"] = ethData.nameServers;
1909 jsonResponse["StaticNameServers"] = ethData.staticNameServers;
1910
1911 nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"];
1912 nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"];
1913 ipv4Array = nlohmann::json::array();
1914 ipv4StaticArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001915 for (const auto& ipv4Config : ipv4Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001916 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001917 std::string gatewayStr = ipv4Config.gateway;
1918 if (gatewayStr.empty())
1919 {
1920 gatewayStr = "0.0.0.0";
1921 }
Ed Tanous14766872022-03-15 10:44:42 -07001922 nlohmann::json::object_t ipv4;
1923 ipv4["AddressOrigin"] = ipv4Config.origin;
1924 ipv4["SubnetMask"] = ipv4Config.netmask;
1925 ipv4["Address"] = ipv4Config.address;
1926 ipv4["Gateway"] = gatewayStr;
Ed Tanousbf648f72021-06-03 15:00:14 -07001927
Ed Tanousbf648f72021-06-03 15:00:14 -07001928 if (ipv4Config.origin == "Static")
1929 {
Ed Tanous14766872022-03-15 10:44:42 -07001930 ipv4StaticArray.push_back(ipv4);
Ed Tanousbf648f72021-06-03 15:00:14 -07001931 }
Ed Tanous14766872022-03-15 10:44:42 -07001932
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001933 ipv4Array.emplace_back(std::move(ipv4));
Ed Tanousbf648f72021-06-03 15:00:14 -07001934 }
1935
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001936 std::string ipv6GatewayStr = ethData.ipv6DefaultGateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001937 if (ipv6GatewayStr.empty())
1938 {
1939 ipv6GatewayStr = "0:0:0:0:0:0:0:0";
1940 }
1941
1942 jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr;
1943
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001944 nlohmann::json::array_t ipv6StaticGatewayArray;
1945 for (const auto& ipv6GatewayConfig : ipv6GatewayData)
1946 {
1947 nlohmann::json::object_t ipv6Gateway;
1948 ipv6Gateway["Address"] = ipv6GatewayConfig.gateway;
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001949 ipv6StaticGatewayArray.emplace_back(std::move(ipv6Gateway));
1950 }
1951 jsonResponse["IPv6StaticDefaultGateways"] =
1952 std::move(ipv6StaticGatewayArray);
1953
Ed Tanousbf648f72021-06-03 15:00:14 -07001954 nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"];
1955 nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"];
1956 ipv6Array = nlohmann::json::array();
1957 ipv6StaticArray = nlohmann::json::array();
1958 nlohmann::json& ipv6AddrPolicyTable =
1959 jsonResponse["IPv6AddressPolicyTable"];
1960 ipv6AddrPolicyTable = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001961 for (const auto& ipv6Config : ipv6Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001962 {
Ed Tanous14766872022-03-15 10:44:42 -07001963 nlohmann::json::object_t ipv6;
1964 ipv6["Address"] = ipv6Config.address;
1965 ipv6["PrefixLength"] = ipv6Config.prefixLength;
1966 ipv6["AddressOrigin"] = ipv6Config.origin;
Sunitha Harishf8361272023-03-16 03:23:59 -05001967
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001968 ipv6Array.emplace_back(std::move(ipv6));
Ed Tanousbf648f72021-06-03 15:00:14 -07001969 if (ipv6Config.origin == "Static")
1970 {
Ed Tanous14766872022-03-15 10:44:42 -07001971 nlohmann::json::object_t ipv6Static;
1972 ipv6Static["Address"] = ipv6Config.address;
1973 ipv6Static["PrefixLength"] = ipv6Config.prefixLength;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001974 ipv6StaticArray.emplace_back(std::move(ipv6Static));
Ed Tanousbf648f72021-06-03 15:00:14 -07001975 }
1976 }
1977}
1978
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08001979inline void afterDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1980 const std::string& ifaceId,
1981 const boost::system::error_code& ec,
1982 const sdbusplus::message_t& m)
1983{
1984 if (!ec)
1985 {
1986 return;
1987 }
1988 const sd_bus_error* dbusError = m.get_error();
1989 if (dbusError == nullptr)
1990 {
1991 messages::internalError(asyncResp->res);
1992 return;
1993 }
Ed Tanous62598e32023-07-17 17:06:25 -07001994 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08001995
1996 if (std::string_view("org.freedesktop.DBus.Error.UnknownObject") ==
1997 dbusError->name)
1998 {
1999 messages::resourceNotFound(asyncResp->res, "EthernetInterface",
2000 ifaceId);
2001 return;
2002 }
2003 if (std::string_view("org.freedesktop.DBus.Error.UnknownMethod") ==
2004 dbusError->name)
2005 {
2006 messages::resourceCannotBeDeleted(asyncResp->res);
2007 return;
2008 }
2009 messages::internalError(asyncResp->res);
2010}
2011
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002012inline void afterVlanCreate(
2013 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2014 const std::string& parentInterfaceUri, const std::string& vlanInterface,
2015 const boost::system::error_code& ec, const sdbusplus::message_t& m
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002016
2017)
2018{
2019 if (ec)
2020 {
2021 const sd_bus_error* dbusError = m.get_error();
2022 if (dbusError == nullptr)
2023 {
2024 messages::internalError(asyncResp->res);
2025 return;
2026 }
Ed Tanous62598e32023-07-17 17:06:25 -07002027 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002028
2029 if (std::string_view(
2030 "xyz.openbmc_project.Common.Error.ResourceNotFound") ==
2031 dbusError->name)
2032 {
2033 messages::propertyValueNotInList(
2034 asyncResp->res, parentInterfaceUri,
2035 "Links/RelatedInterfaces/0/@odata.id");
2036 return;
2037 }
2038 if (std::string_view(
2039 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
2040 dbusError->name)
2041 {
2042 messages::resourceAlreadyExists(asyncResp->res, "EthernetInterface",
2043 "Id", vlanInterface);
2044 return;
2045 }
2046 messages::internalError(asyncResp->res);
2047 return;
2048 }
2049
Ed Tanous253f11b2024-05-16 09:38:31 -07002050 const boost::urls::url vlanInterfaceUri =
2051 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2052 BMCWEB_REDFISH_MANAGER_URI_NAME, vlanInterface);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002053 asyncResp->res.addHeader("Location", vlanInterfaceUri.buffer());
2054}
2055
Ed Tanousbf648f72021-06-03 15:00:14 -07002056inline void requestEthernetInterfacesRoutes(App& app)
2057{
Ed Tanous253f11b2024-05-16 09:38:31 -07002058 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Ed Tanoused398212021-06-09 17:05:54 -07002059 .privileges(redfish::privileges::getEthernetInterfaceCollection)
Ed Tanous14766872022-03-15 10:44:42 -07002060 .methods(boost::beast::http::verb::get)(
2061 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002062 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2063 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002064 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2065 {
2066 return;
2067 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002068
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002069 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2070 {
2071 messages::resourceNotFound(asyncResp->res, "Manager",
2072 managerId);
2073 return;
2074 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002075
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002076 asyncResp->res.jsonValue["@odata.type"] =
2077 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
2078 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2079 "/redfish/v1/Managers/{}/EthernetInterfaces",
2080 BMCWEB_REDFISH_MANAGER_URI_NAME);
2081 asyncResp->res.jsonValue["Name"] =
2082 "Ethernet Network Interface Collection";
2083 asyncResp->res.jsonValue["Description"] =
2084 "Collection of EthernetInterfaces for this Manager";
2085
2086 // Get eth interface list, and call the below callback for JSON
2087 // preparation
2088 getEthernetIfaceList(
2089 [asyncResp](const bool& success,
2090 const std::vector<std::string>& ifaceList) {
2091 if (!success)
2092 {
2093 messages::internalError(asyncResp->res);
2094 return;
2095 }
2096
2097 nlohmann::json& ifaceArray =
2098 asyncResp->res.jsonValue["Members"];
2099 ifaceArray = nlohmann::json::array();
2100 for (const std::string& ifaceItem : ifaceList)
2101 {
2102 nlohmann::json::object_t iface;
2103 iface["@odata.id"] = boost::urls::format(
2104 "/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2105 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceItem);
2106 ifaceArray.push_back(std::move(iface));
2107 }
2108
2109 asyncResp->res.jsonValue["Members@odata.count"] =
2110 ifaceArray.size();
2111 asyncResp->res.jsonValue["@odata.id"] =
2112 boost::urls::format(
2113 "/redfish/v1/Managers/{}/EthernetInterfaces",
Ed Tanous253f11b2024-05-16 09:38:31 -07002114 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002115 });
2116 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002117
Ed Tanous253f11b2024-05-16 09:38:31 -07002118 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002119 .privileges(redfish::privileges::postEthernetInterfaceCollection)
2120 .methods(boost::beast::http::verb::post)(
2121 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002122 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2123 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002124 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2125 {
2126 return;
2127 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002128
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002129 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2130 {
2131 messages::resourceNotFound(asyncResp->res, "Manager",
2132 managerId);
2133 return;
2134 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002135
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002136 bool vlanEnable = false;
2137 uint32_t vlanId = 0;
2138 std::vector<nlohmann::json::object_t> relatedInterfaces;
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002139
Myung Baeafc474a2024-10-09 00:53:29 -07002140 if (!json_util::readJsonPatch( //
2141 req, asyncResp->res, //
2142 "Links/RelatedInterfaces", relatedInterfaces, //
2143 "VLAN/VLANEnable", vlanEnable, //
2144 "VLAN/VLANId", vlanId //
2145 ))
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002146 {
2147 return;
2148 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002149
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002150 if (relatedInterfaces.size() != 1)
2151 {
2152 messages::arraySizeTooLong(asyncResp->res,
2153 "Links/RelatedInterfaces",
2154 relatedInterfaces.size());
2155 return;
2156 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002157
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002158 std::string parentInterfaceUri;
2159 if (!json_util::readJsonObject(relatedInterfaces[0],
2160 asyncResp->res, "@odata.id",
2161 parentInterfaceUri))
2162 {
2163 messages::propertyMissing(
2164 asyncResp->res, "Links/RelatedInterfaces/0/@odata.id");
2165 return;
2166 }
2167 BMCWEB_LOG_INFO("Parent Interface URI: {}", parentInterfaceUri);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002168
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002169 boost::system::result<boost::urls::url_view> parsedUri =
2170 boost::urls::parse_relative_ref(parentInterfaceUri);
2171 if (!parsedUri)
2172 {
2173 messages::propertyValueFormatError(
2174 asyncResp->res, parentInterfaceUri,
2175 "Links/RelatedInterfaces/0/@odata.id");
2176 return;
2177 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002178
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002179 std::string parentInterface;
2180 if (!crow::utility::readUrlSegments(
2181 *parsedUri, "redfish", "v1", "Managers", "bmc",
2182 "EthernetInterfaces", std::ref(parentInterface)))
2183 {
2184 messages::propertyValueNotInList(
2185 asyncResp->res, parentInterfaceUri,
2186 "Links/RelatedInterfaces/0/@odata.id");
2187 return;
2188 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002189
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002190 if (!vlanEnable)
2191 {
2192 // In OpenBMC implementation, VLANEnable cannot be false on
2193 // create
2194 messages::propertyValueIncorrect(
2195 asyncResp->res, "VLAN/VLANEnable", "false");
2196 return;
2197 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002198
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002199 std::string vlanInterface =
2200 parentInterface + "_" + std::to_string(vlanId);
2201 crow::connections::systemBus->async_method_call(
2202 [asyncResp, parentInterfaceUri,
2203 vlanInterface](const boost::system::error_code& ec,
2204 const sdbusplus::message_t& m) {
2205 afterVlanCreate(asyncResp, parentInterfaceUri,
2206 vlanInterface, ec, m);
2207 },
2208 "xyz.openbmc_project.Network",
2209 "/xyz/openbmc_project/network",
2210 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
2211 parentInterface, vlanId);
2212 });
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002213
Ed Tanous253f11b2024-05-16 09:38:31 -07002214 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002215 .privileges(redfish::privileges::getEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002216 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002217 [&app](const crow::Request& req,
2218 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002219 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002220 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2221 {
2222 return;
2223 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002224
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002225 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2226 {
2227 messages::resourceNotFound(asyncResp->res, "Manager",
2228 managerId);
2229 return;
2230 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002231
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002232 getEthernetIfaceData(
2233 ifaceId,
2234 [asyncResp, ifaceId](
2235 const bool& success,
2236 const EthernetInterfaceData& ethData,
2237 const std::vector<IPv4AddressData>& ipv4Data,
2238 const std::vector<IPv6AddressData>& ipv6Data,
2239 const std::vector<StaticGatewayData>& ipv6GatewayData) {
2240 if (!success)
2241 {
2242 // TODO(Pawel)consider distinguish between non
2243 // existing object, and other errors
2244 messages::resourceNotFound(
2245 asyncResp->res, "EthernetInterface", ifaceId);
2246 return;
2247 }
Johnathan Mantey01784822019-06-18 12:44:21 -07002248
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002249 asyncResp->res.jsonValue["@odata.type"] =
2250 "#EthernetInterface.v1_9_0.EthernetInterface";
2251 asyncResp->res.jsonValue["Name"] =
2252 "Manager Ethernet Interface";
2253 asyncResp->res.jsonValue["Description"] =
2254 "Management Network Interface";
Ratan Guptaf476acb2019-03-02 16:46:57 +05302255
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002256 parseInterfaceData(asyncResp, ifaceId, ethData,
2257 ipv4Data, ipv6Data, ipv6GatewayData);
2258 });
2259 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002260
Ed Tanous253f11b2024-05-16 09:38:31 -07002261 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002262 .privileges(redfish::privileges::patchEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002263 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002264 [&app](const crow::Request& req,
2265 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002266 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002267 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2268 {
2269 return;
2270 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002271
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002272 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2273 {
2274 messages::resourceNotFound(asyncResp->res, "Manager",
2275 managerId);
2276 return;
2277 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002278
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002279 std::optional<std::string> hostname;
2280 std::optional<std::string> fqdn;
2281 std::optional<std::string> macAddress;
2282 std::optional<std::string> ipv6DefaultGateway;
2283 std::optional<std::vector<
2284 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2285 ipv4StaticAddresses;
2286 std::optional<std::vector<
2287 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2288 ipv6StaticAddresses;
2289 std::optional<std::vector<
2290 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2291 ipv6StaticDefaultGateways;
2292 std::optional<std::vector<std::string>> staticNameServers;
2293 std::optional<bool> ipv6AutoConfigEnabled;
2294 std::optional<bool> interfaceEnabled;
2295 std::optional<size_t> mtuSize;
2296 DHCPParameters v4dhcpParms;
2297 DHCPParameters v6dhcpParms;
Myung Baeafc474a2024-10-09 00:53:29 -07002298
2299 if (!json_util::readJsonPatch( //
2300 req, asyncResp->res, //
2301 "DHCPv4/DHCPEnabled", v4dhcpParms.dhcpv4Enabled, //
2302 "DHCPv4/UseDNSServers", v4dhcpParms.useDnsServers, //
2303 "DHCPv4/UseDomainName", v4dhcpParms.useDomainName, //
2304 "DHCPv4/UseNTPServers", v4dhcpParms.useNtpServers, //
2305 "DHCPv6/OperatingMode",
2306 v6dhcpParms.dhcpv6OperatingMode, //
2307 "DHCPv6/UseDNSServers", v6dhcpParms.useDnsServers, //
2308 "DHCPv6/UseDomainName", v6dhcpParms.useDomainName, //
2309 "DHCPv6/UseNTPServers", v6dhcpParms.useNtpServers, //
2310 "FQDN", fqdn, //
2311 "HostName", hostname, //
2312 "InterfaceEnabled", interfaceEnabled, //
2313 "IPv4StaticAddresses", ipv4StaticAddresses, //
2314 "IPv6DefaultGateway", ipv6DefaultGateway, //
2315 "IPv6StaticAddresses", ipv6StaticAddresses, //
2316 "IPv6StaticDefaultGateways",
2317 ipv6StaticDefaultGateways, //
2318 "InterfaceEnabled", interfaceEnabled, //
2319 "MACAddress", macAddress, //
2320 "MTUSize", mtuSize, //
2321 "StatelessAddressAutoConfig/IPv6AutoConfigEnabled",
2322 ipv6AutoConfigEnabled, //
2323 "StaticNameServers", staticNameServers //
2324 ))
2325 {
2326 return;
2327 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002328
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002329 // Get single eth interface data, and call the below callback
2330 // for JSON preparation
2331 getEthernetIfaceData(
2332 ifaceId,
2333 [asyncResp, ifaceId, hostname = std::move(hostname),
2334 fqdn = std::move(fqdn), macAddress = std::move(macAddress),
2335 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
2336 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
2337 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
2338 ipv6StaticDefaultGateway =
2339 std::move(ipv6StaticDefaultGateways),
2340 staticNameServers = std::move(staticNameServers), mtuSize,
2341 ipv6AutoConfigEnabled,
2342 v4dhcpParms = std::move(v4dhcpParms),
2343 v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled](
2344 const bool success,
2345 const EthernetInterfaceData& ethData,
2346 const std::vector<IPv4AddressData>& ipv4Data,
2347 const std::vector<IPv6AddressData>& ipv6Data,
2348 const std::vector<StaticGatewayData>&
2349 ipv6GatewayData) mutable {
2350 if (!success)
2351 {
2352 // ... otherwise return error
2353 // TODO(Pawel)consider distinguish between non
2354 // existing object, and other errors
2355 messages::resourceNotFound(
2356 asyncResp->res, "EthernetInterface", ifaceId);
2357 return;
2358 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002359
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002360 handleDHCPPatch(ifaceId, ethData, v4dhcpParms,
2361 v6dhcpParms, asyncResp);
Tejas Patil35fb5312021-09-20 15:35:20 +05302362
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002363 if (hostname)
2364 {
2365 handleHostnamePatch(*hostname, asyncResp);
2366 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002367
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002368 if (ipv6AutoConfigEnabled)
2369 {
2370 handleSLAACAutoConfigPatch(
2371 ifaceId, *ipv6AutoConfigEnabled, asyncResp);
2372 }
Ravi Tejab10d8db2022-05-24 09:04:12 -05002373
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002374 if (fqdn)
2375 {
2376 handleFqdnPatch(ifaceId, *fqdn, asyncResp);
2377 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002378
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002379 if (macAddress)
2380 {
2381 handleMACAddressPatch(ifaceId, *macAddress,
2382 asyncResp);
2383 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002384
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002385 if (ipv4StaticAddresses)
2386 {
2387 handleIPv4StaticPatch(ifaceId, *ipv4StaticAddresses,
2388 ethData, ipv4Data, asyncResp);
2389 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002390
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002391 if (staticNameServers)
2392 {
2393 handleStaticNameServersPatch(
2394 ifaceId, *staticNameServers, asyncResp);
2395 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002396
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002397 if (ipv6DefaultGateway)
2398 {
2399 messages::propertyNotWritable(asyncResp->res,
2400 "IPv6DefaultGateway");
2401 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002402
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002403 if (ipv6StaticAddresses)
2404 {
2405 handleIPv6StaticAddressesPatch(ifaceId,
2406 *ipv6StaticAddresses,
2407 ipv6Data, asyncResp);
2408 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002409
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002410 if (ipv6StaticDefaultGateway)
2411 {
2412 handleIPv6DefaultGateway(
2413 ifaceId, *ipv6StaticDefaultGateway,
2414 ipv6GatewayData, asyncResp);
2415 }
Sunitha Harishce73d5c2023-04-07 06:46:49 -05002416
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002417 if (interfaceEnabled)
2418 {
2419 setDbusProperty(
2420 asyncResp, "InterfaceEnabled",
Ginu Georgee93abac2024-06-14 17:35:27 +05302421 "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08002422 sdbusplus::message::object_path(
2423 "/xyz/openbmc_project/network") /
2424 ifaceId,
2425 "xyz.openbmc_project.Network.EthernetInterface",
Ginu Georgee93abac2024-06-14 17:35:27 +05302426 "NICEnabled", *interfaceEnabled);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002427 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002428
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002429 if (mtuSize)
2430 {
2431 handleMTUSizePatch(ifaceId, *mtuSize, asyncResp);
2432 }
2433 });
2434 });
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002435
Ed Tanous253f11b2024-05-16 09:38:31 -07002436 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002437 .privileges(redfish::privileges::deleteEthernetInterface)
2438 .methods(boost::beast::http::verb::delete_)(
2439 [&app](const crow::Request& req,
2440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002441 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002442 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2443 {
2444 return;
2445 }
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002446
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002447 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2448 {
2449 messages::resourceNotFound(asyncResp->res, "Manager",
2450 managerId);
2451 return;
2452 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002453
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002454 crow::connections::systemBus->async_method_call(
2455 [asyncResp, ifaceId](const boost::system::error_code& ec,
2456 const sdbusplus::message_t& m) {
2457 afterDelete(asyncResp, ifaceId, ec, m);
2458 },
2459 "xyz.openbmc_project.Network",
2460 std::string("/xyz/openbmc_project/network/") + ifaceId,
2461 "xyz.openbmc_project.Object.Delete", "Delete");
2462 });
Ed Tanousbf648f72021-06-03 15:00:14 -07002463}
2464
Ed Tanous1abe55e2018-09-05 08:30:59 -07002465} // namespace redfish