blob: 34e7215119dff01d48f9af542864edb84e134a9f [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070022#include "generated/enums/ethernet_interface.hpp"
23#include "generated/enums/resource.hpp"
Ed Tanous2c5875a2023-05-15 09:56:06 -070024#include "human_sort.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "query.hpp"
26#include "registries/privilege_registry.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070027#include "utils/ip_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080028#include "utils/json_utils.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070029
Sunitha Harishce73d5c2023-04-07 06:46:49 -050030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032
George Liu7a1dbc42022-12-07 16:03:22 +080033#include <array>
Ed Tanous3dfed532024-03-06 14:41:27 -080034#include <cstddef>
Sunitha Harishce73d5c2023-04-07 06:46:49 -050035#include <memory>
Ed Tanousa24526d2018-12-10 15:17:59 -080036#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070037#include <ranges>
Joshi-Mansiab6554f2020-03-10 18:33:36 +053038#include <regex>
George Liu7a1dbc42022-12-07 16:03:22 +080039#include <string_view>
Ed Tanous3dfed532024-03-06 14:41:27 -080040#include <variant>
Ed Tanous77179532023-02-28 10:45:28 -080041#include <vector>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010042
Ed Tanous1abe55e2018-09-05 08:30:59 -070043namespace redfish
44{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010045
Ed Tanous4a0cb852018-10-15 07:55:04 -070046enum class LinkType
47{
48 Local,
49 Global
50};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010051
Johnathan Mantey743eb1c2024-04-03 12:05:57 -070052enum class IpVersion
53{
54 IpV4,
55 IpV6
56};
57
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010058/**
59 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010060 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070061struct IPv4AddressData
62{
63 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070064 std::string address;
65 std::string domain;
66 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 std::string netmask;
68 std::string origin;
Ed Tanous77179532023-02-28 10:45:28 -080069 LinkType linktype{};
70 bool isActive{};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
Ed Tanous77179532023-02-28 10:45:28 -080081 uint8_t prefixLength = 0;
Ravi Tejae48c0fc2019-04-16 08:37:20 -050082};
Sunitha Harishce73d5c2023-04-07 06:46:49 -050083
84/**
85 * Structure for keeping static route data required by Redfish
86 */
87struct StaticGatewayData
88{
89 std::string id;
90 std::string gateway;
91 size_t prefixLength = 0;
92 std::string protocol;
93};
94
Ravi Tejae48c0fc2019-04-16 08:37:20 -050095/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010096 * Structure for keeping basic single Ethernet Interface information
97 * available from DBus
98 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070099struct EthernetInterfaceData
100{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700101 uint32_t speed;
Tejas Patil35fb5312021-09-20 15:35:20 +0530102 size_t mtuSize;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800103 bool autoNeg;
Jishnu CMe4588152023-05-11 00:04:40 -0500104 bool dnsv4Enabled;
105 bool dnsv6Enabled;
Ravi Teja91c441e2024-02-23 09:03:43 -0600106 bool domainv4Enabled;
107 bool domainv6Enabled;
Jishnu CMe4588152023-05-11 00:04:40 -0500108 bool ntpv4Enabled;
109 bool ntpv6Enabled;
110 bool hostNamev4Enabled;
111 bool hostNamev6Enabled;
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800112 bool linkUp;
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700113 bool nicEnabled;
Ravi Tejab10d8db2022-05-24 09:04:12 -0500114 bool ipv6AcceptRa;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800115 std::string dhcpEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700116 std::string operatingMode;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800117 std::string hostName;
118 std::string defaultGateway;
119 std::string ipv6DefaultGateway;
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500120 std::string ipv6StaticDefaultGateway;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800121 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,
862 "Gateway", staticGateway.gateway, "PrefixLength",
863 staticGateway.prefixLength, "ProtocolType",
864 staticGateway.protocol);
865 if (!success)
866 {
867 return false;
868 }
869 }
870 }
871 return true;
872}
873
Johnathan Mantey01784822019-06-18 12:44:21 -0700874/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500875 * @brief Creates IPv6 with given data
876 *
877 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500878 * @param[in] prefixLength Prefix length that needs to be added
879 * @param[in] address IP address that needs to be added
880 * @param[io] asyncResp Response object that will be returned to client
881 *
882 * @return None
883 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500884inline void createIPv6(const std::string& ifaceId, uint8_t prefixLength,
885 const std::string& address,
zhanghch058d1b46d2021-04-01 11:18:24 +0800886 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500887{
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500888 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
889 path /= ifaceId;
890
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400891 auto createIpHandler =
892 [asyncResp, address](const boost::system::error_code& ec) {
893 if (ec)
Nitin Kumar Kotaniafc23ef82023-06-29 04:55:09 -0500894 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400895 if (ec == boost::system::errc::io_error)
896 {
897 messages::propertyValueFormatError(asyncResp->res, address,
898 "Address");
899 }
900 else
901 {
902 messages::internalError(asyncResp->res);
903 }
Nitin Kumar Kotaniafc23ef82023-06-29 04:55:09 -0500904 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400905 };
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500906 // Passing null for gateway, as per redfish spec IPv6StaticAddresses
907 // object does not have associated gateway property
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500908 crow::connections::systemBus->async_method_call(
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500909 std::move(createIpHandler), "xyz.openbmc_project.Network", path,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500910 "xyz.openbmc_project.Network.IP.Create", "IP",
911 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
912 "");
913}
914
Ed Tanous4a0cb852018-10-15 07:55:04 -0700915/**
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500916 * @brief Deletes given IPv6 Static Gateway
917 *
918 * @param[in] ifaceId Id of interface whose IP should be deleted
919 * @param[in] ipHash DBus Hash id of IP that should be deleted
920 * @param[io] asyncResp Response object that will be returned to client
921 *
922 * @return None
923 */
924inline void
925 deleteIPv6Gateway(std::string_view gatewayId,
926 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
927{
928 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
929 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
945 * @param[in] prefixLength Prefix length that needs to be added
946 * @param[in] gateway Gateway address that needs to be added
947 * @param[io] asyncResp Response object that will be returned to client
948 *
949 * @return None
950 */
951inline void createIPv6DefaultGateway(
952 std::string_view ifaceId, size_t prefixLength, std::string_view gateway,
953 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
954{
955 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
956 path /= ifaceId;
957 auto createIpHandler = [asyncResp](const boost::system::error_code& ec) {
958 if (ec)
959 {
960 messages::internalError(asyncResp->res);
961 }
962 };
963 crow::connections::systemBus->async_method_call(
964 std::move(createIpHandler), "xyz.openbmc_project.Network", path,
965 "xyz.openbmc_project.Network.StaticGateway.Create", "StaticGateway",
966 gateway, prefixLength, "xyz.openbmc_project.Network.IP.Protocol.IPv6");
967}
968
969/**
970 * @brief Deletes the IPv6 default gateway entry for this interface and
971 * creates a replacement IPv6 default gateway entry
972 *
973 * @param[in] ifaceId Id of interface upon which to create the IPv6
974 * entry
975 * @param[in] gateway IPv6 gateway to assign to this interface
976 * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
977 * @param[io] asyncResp Response object that will be returned to client
978 *
979 * @return None
980 */
981inline void deleteAndCreateIPv6DefaultGateway(
982 std::string_view ifaceId, std::string_view gatewayId,
983 std::string_view gateway, size_t prefixLength,
984 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
985{
986 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
987 path /= gatewayId;
988 crow::connections::systemBus->async_method_call(
989 [asyncResp, ifaceId, gateway,
990 prefixLength](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400991 if (ec)
992 {
993 messages::internalError(asyncResp->res);
994 return;
995 }
996 createIPv6DefaultGateway(ifaceId, prefixLength, gateway, asyncResp);
997 },
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500998 "xyz.openbmc_project.Network", path,
999 "xyz.openbmc_project.Object.Delete", "Delete");
1000}
1001
1002/**
1003 * @brief Sets IPv6 default gateway with given data
1004 *
1005 * @param[in] ifaceId Id of interface whose gateway should be added
1006 * @param[in] input Contains address that needs to be added
1007 * @param[in] staticGatewayData Current static gateways in the system
1008 * @param[io] asyncResp Response object that will be returned to client
1009 *
1010 * @return None
1011 */
1012
1013inline void handleIPv6DefaultGateway(
Ed Tanous3dfed532024-03-06 14:41:27 -08001014 const std::string& ifaceId,
1015 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001016 const std::vector<StaticGatewayData>& staticGatewayData,
1017 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1018{
1019 size_t entryIdx = 1;
1020 std::vector<StaticGatewayData>::const_iterator staticGatewayEntry =
1021 staticGatewayData.begin();
1022
Ed Tanous3dfed532024-03-06 14:41:27 -08001023 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1024 input)
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001025 {
1026 // find the next gateway entry
1027 while (staticGatewayEntry != staticGatewayData.end())
1028 {
1029 if (staticGatewayEntry->protocol ==
1030 "xyz.openbmc_project.Network.IP.Protocol.IPv6")
1031 {
1032 break;
1033 }
1034 staticGatewayEntry++;
1035 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001036 std::string pathString =
1037 "IPv6StaticDefaultGateways/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001038 nlohmann::json::object_t* obj =
1039 std::get_if<nlohmann::json::object_t>(&thisJson);
1040 if (obj == nullptr)
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001041 {
1042 if (staticGatewayEntry == staticGatewayData.end())
1043 {
1044 messages::resourceCannotBeDeleted(asyncResp->res);
1045 return;
1046 }
1047 deleteIPv6Gateway(staticGatewayEntry->id, asyncResp);
1048 return;
1049 }
Ed Tanous3dfed532024-03-06 14:41:27 -08001050 if (obj->empty())
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001051 {
1052 // Do nothing, but make sure the entry exists.
1053 if (staticGatewayEntry == staticGatewayData.end())
1054 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001055 messages::propertyValueFormatError(asyncResp->res, *obj,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001056 pathString);
1057 return;
1058 }
1059 }
1060 std::optional<std::string> address;
1061 std::optional<size_t> prefixLength;
1062
Ed Tanous3dfed532024-03-06 14:41:27 -08001063 if (!json_util::readJsonObject(*obj, asyncResp->res, "Address", address,
1064 "PrefixLength", prefixLength))
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001065 {
1066 return;
1067 }
1068 const std::string* addr = nullptr;
1069 size_t prefix = 0;
1070 if (address)
1071 {
1072 addr = &(*address);
1073 }
1074 else if (staticGatewayEntry != staticGatewayData.end())
1075 {
1076 addr = &(staticGatewayEntry->gateway);
1077 }
1078 else
1079 {
1080 messages::propertyMissing(asyncResp->res, pathString + "/Address");
1081 return;
1082 }
1083 if (prefixLength)
1084 {
1085 prefix = *prefixLength;
1086 }
1087 else if (staticGatewayEntry != staticGatewayData.end())
1088 {
1089 prefix = staticGatewayEntry->prefixLength;
1090 }
1091 else
1092 {
1093 messages::propertyMissing(asyncResp->res,
1094 pathString + "/PrefixLength");
1095 return;
1096 }
1097 if (staticGatewayEntry != staticGatewayData.end())
1098 {
1099 deleteAndCreateIPv6DefaultGateway(ifaceId, staticGatewayEntry->id,
1100 *addr, prefix, asyncResp);
1101 staticGatewayEntry++;
1102 }
1103 else
1104 {
1105 createIPv6DefaultGateway(ifaceId, prefix, *addr, asyncResp);
1106 }
1107 entryIdx++;
1108 }
1109}
1110
1111/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001112 * Function that retrieves all properties for given Ethernet Interface
1113 * Object
1114 * from EntityManager Network Manager
1115 * @param ethiface_id a eth interface id to query on DBus
1116 * @param callback a function that shall be called to convert Dbus output
1117 * into JSON
1118 */
1119template <typename CallbackFunc>
Ed Tanous81ce6092020-12-17 16:54:55 +00001120void getEthernetIfaceData(const std::string& ethifaceId,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001121 CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001122{
George Liuf5892d02023-03-01 10:37:08 +08001123 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1124 dbus::utility::getManagedObjects(
1125 "xyz.openbmc_project.Network", path,
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001126 [ethifaceId{std::string{ethifaceId}},
Ed Tanous8cb2c022024-03-27 16:31:46 -07001127 callback = std::forward<CallbackFunc>(callback)](
Ed Tanous8b242752023-06-27 17:17:13 -07001128 const boost::system::error_code& ec,
Ed Tanous3dfed532024-03-06 14:41:27 -08001129 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001130 EthernetInterfaceData ethData{};
1131 std::vector<IPv4AddressData> ipv4Data;
1132 std::vector<IPv6AddressData> ipv6Data;
1133 std::vector<StaticGatewayData> ipv6GatewayData;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001134
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001135 if (ec)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001136 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001137 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1138 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001139 }
1140
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001141 bool found =
1142 extractEthernetInterfaceData(ethifaceId, resp, ethData);
1143 if (!found)
1144 {
1145 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1146 return;
1147 }
1148
1149 extractIPData(ethifaceId, resp, ipv4Data);
1150 // Fix global GW
1151 for (IPv4AddressData& ipv4 : ipv4Data)
1152 {
1153 if (((ipv4.linktype == LinkType::Global) &&
1154 (ipv4.gateway == "0.0.0.0")) ||
1155 (ipv4.origin == "DHCP") || (ipv4.origin == "Static"))
1156 {
1157 ipv4.gateway = ethData.defaultGateway;
1158 }
1159 }
1160
1161 extractIPV6Data(ethifaceId, resp, ipv6Data);
1162 if (!extractIPv6DefaultGatewayData(ethifaceId, resp,
1163 ipv6GatewayData))
1164 {
1165 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1166 }
1167 // Finally make a callback with useful data
1168 callback(true, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1169 });
Ed Tanous271584a2019-07-09 16:24:22 -07001170}
Ed Tanous4a0cb852018-10-15 07:55:04 -07001171
1172/**
1173 * Function that retrieves all Ethernet Interfaces available through Network
1174 * Manager
1175 * @param callback a function that shall be called to convert Dbus output
1176 * into JSON.
1177 */
1178template <typename CallbackFunc>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001179void getEthernetIfaceList(CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001180{
George Liuf5892d02023-03-01 10:37:08 +08001181 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1182 dbus::utility::getManagedObjects(
1183 "xyz.openbmc_project.Network", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001184 [callback = std::forward<CallbackFunc>(callback)](
Ed Tanous8b242752023-06-27 17:17:13 -07001185 const boost::system::error_code& ec,
George Liuf5892d02023-03-01 10:37:08 +08001186 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001187 // Callback requires vector<string> to retrieve all available
1188 // ethernet interfaces
1189 std::vector<std::string> ifaceList;
1190 ifaceList.reserve(resp.size());
1191 if (ec)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001192 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001193 callback(false, ifaceList);
1194 return;
1195 }
1196
1197 // Iterate over all retrieved ObjectPaths.
1198 for (const auto& objpath : resp)
1199 {
1200 // And all interfaces available for certain ObjectPath.
1201 for (const auto& interface : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001202 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001203 // If interface is
1204 // xyz.openbmc_project.Network.EthernetInterface, this is
1205 // what we're looking for.
1206 if (interface.first ==
1207 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001209 std::string ifaceId = objpath.first.filename();
1210 if (ifaceId.empty())
1211 {
1212 continue;
1213 }
1214 // and put it into output vector.
1215 ifaceList.emplace_back(ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 }
1217 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001218 }
Ed Tanous2c5875a2023-05-15 09:56:06 -07001219
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001220 std::ranges::sort(ifaceList, AlphanumLess<std::string>());
Ed Tanous2c5875a2023-05-15 09:56:06 -07001221
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001222 // Finally make a callback with useful data
1223 callback(true, ifaceList);
1224 });
Ed Tanous271584a2019-07-09 16:24:22 -07001225}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001226
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001227inline void
1228 handleHostnamePatch(const std::string& hostname,
1229 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001230{
Ed Tanousbf648f72021-06-03 15:00:14 -07001231 // SHOULD handle host names of up to 255 characters(RFC 1123)
1232 if (hostname.length() > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001234 messages::propertyValueFormatError(asyncResp->res, hostname,
1235 "HostName");
1236 return;
1237 }
Ed Tanousd02aad32024-02-13 14:43:34 -08001238 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301239 asyncResp, "HostName", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001240 sdbusplus::message::object_path("/xyz/openbmc_project/network/config"),
1241 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ginu Georgee93abac2024-06-14 17:35:27 +05301242 hostname);
Ed Tanousbf648f72021-06-03 15:00:14 -07001243}
1244
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001245inline void
Tejas Patil35fb5312021-09-20 15:35:20 +05301246 handleMTUSizePatch(const std::string& ifaceId, const size_t mtuSize,
1247 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1248{
Ed Tanousd02aad32024-02-13 14:43:34 -08001249 sdbusplus::message::object_path objPath("/xyz/openbmc_project/network");
1250 objPath /= ifaceId;
Ginu Georgee93abac2024-06-14 17:35:27 +05301251 setDbusProperty(asyncResp, "MTUSize", "xyz.openbmc_project.Network",
1252 objPath, "xyz.openbmc_project.Network.EthernetInterface",
1253 "MTU", mtuSize);
Tejas Patil35fb5312021-09-20 15:35:20 +05301254}
1255
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001256inline void handleDomainnamePatch(
1257 const std::string& ifaceId, const std::string& domainname,
1258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001259{
1260 std::vector<std::string> vectorDomainname = {domainname};
Ed Tanousd02aad32024-02-13 14:43:34 -08001261 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301262 asyncResp, "FQDN", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001263 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1264 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301265 "xyz.openbmc_project.Network.EthernetInterface", "DomainName",
Ed Tanousd02aad32024-02-13 14:43:34 -08001266 vectorDomainname);
Ed Tanousbf648f72021-06-03 15:00:14 -07001267}
1268
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001269inline bool isHostnameValid(const std::string& hostname)
Ed Tanousbf648f72021-06-03 15:00:14 -07001270{
1271 // A valid host name can never have the dotted-decimal form (RFC 1123)
Ed Tanous3544d2a2023-08-06 18:12:20 -07001272 if (std::ranges::all_of(hostname, ::isdigit))
Ed Tanousbf648f72021-06-03 15:00:14 -07001273 {
1274 return false;
1275 }
1276 // Each label(hostname/subdomains) within a valid FQDN
1277 // MUST handle host names of up to 63 characters (RFC 1123)
1278 // labels cannot start or end with hyphens (RFC 952)
1279 // labels can start with numbers (RFC 1123)
Ed Tanous4b242742023-05-11 09:51:51 -07001280 const static std::regex pattern(
Ed Tanousbf648f72021-06-03 15:00:14 -07001281 "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$");
1282
1283 return std::regex_match(hostname, pattern);
1284}
1285
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001286inline bool isDomainnameValid(const std::string& domainname)
Ed Tanousbf648f72021-06-03 15:00:14 -07001287{
1288 // Can have multiple subdomains
1289 // Top Level Domain's min length is 2 character
Ed Tanous4b242742023-05-11 09:51:51 -07001290 const static std::regex pattern(
George Liu0fda0f12021-11-16 10:06:17 +08001291 "^([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 -07001292
1293 return std::regex_match(domainname, pattern);
1294}
1295
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001296inline void handleFqdnPatch(const std::string& ifaceId, const std::string& fqdn,
1297 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001298{
1299 // Total length of FQDN must not exceed 255 characters(RFC 1035)
1300 if (fqdn.length() > 255)
1301 {
1302 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1303 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001304 }
1305
Ed Tanousbf648f72021-06-03 15:00:14 -07001306 size_t pos = fqdn.find('.');
1307 if (pos == std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001308 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001309 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1310 return;
1311 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001312
Ed Tanousbf648f72021-06-03 15:00:14 -07001313 std::string hostname;
1314 std::string domainname;
1315 domainname = (fqdn).substr(pos + 1);
1316 hostname = (fqdn).substr(0, pos);
1317
1318 if (!isHostnameValid(hostname) || !isDomainnameValid(domainname))
1319 {
1320 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1321 return;
1322 }
1323
1324 handleHostnamePatch(hostname, asyncResp);
1325 handleDomainnamePatch(ifaceId, domainname, asyncResp);
1326}
1327
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001328inline void handleMACAddressPatch(
1329 const std::string& ifaceId, const std::string& macAddress,
1330 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001331{
Ed Tanousd02aad32024-02-13 14:43:34 -08001332 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301333 asyncResp, "MACAddress", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001334 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1335 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301336 "xyz.openbmc_project.Network.MACAddress", "MACAddress", macAddress);
Ed Tanousbf648f72021-06-03 15:00:14 -07001337}
1338
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001339inline void setDHCPEnabled(const std::string& ifaceId,
1340 const std::string& propertyName, const bool v4Value,
1341 const bool v6Value,
1342 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001343{
1344 const std::string dhcp = getDhcpEnabledEnumeration(v4Value, v6Value);
Ed Tanousd02aad32024-02-13 14:43:34 -08001345 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301346 asyncResp, "DHCPv4", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001347 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1348 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301349 "xyz.openbmc_project.Network.EthernetInterface", propertyName, dhcp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001350}
1351
Jishnu CMe4588152023-05-11 00:04:40 -05001352enum class NetworkType
1353{
1354 dhcp4,
1355 dhcp6
1356};
1357
1358inline void setDHCPConfig(const std::string& propertyName, const bool& value,
1359 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1360 const std::string& ethifaceId, NetworkType type)
Ed Tanousbf648f72021-06-03 15:00:14 -07001361{
Ed Tanous62598e32023-07-17 17:06:25 -07001362 BMCWEB_LOG_DEBUG("{} = {}", propertyName, value);
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001363 std::string redfishPropertyName;
Jishnu CMe4588152023-05-11 00:04:40 -05001364 sdbusplus::message::object_path path("/xyz/openbmc_project/network/");
1365 path /= ethifaceId;
1366
1367 if (type == NetworkType::dhcp4)
1368 {
1369 path /= "dhcp4";
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001370 redfishPropertyName = "DHCPv4";
Jishnu CMe4588152023-05-11 00:04:40 -05001371 }
1372 else
1373 {
1374 path /= "dhcp6";
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001375 redfishPropertyName = "DHCPv6";
Jishnu CMe4588152023-05-11 00:04:40 -05001376 }
1377
Ginu Georgee93abac2024-06-14 17:35:27 +05301378 setDbusProperty(
1379 asyncResp, redfishPropertyName, "xyz.openbmc_project.Network", path,
1380 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName, value);
Ed Tanousbf648f72021-06-03 15:00:14 -07001381}
1382
Ravi Tejab10d8db2022-05-24 09:04:12 -05001383inline void handleSLAACAutoConfigPatch(
1384 const std::string& ifaceId, bool ipv6AutoConfigEnabled,
1385 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1386{
1387 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1388 path /= ifaceId;
Ginu Georgee93abac2024-06-14 17:35:27 +05301389 setDbusProperty(asyncResp,
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001390 "StatelessAddressAutoConfig/IPv6AutoConfigEnabled",
Ginu Georgee93abac2024-06-14 17:35:27 +05301391 "xyz.openbmc_project.Network", path,
1392 "xyz.openbmc_project.Network.EthernetInterface",
1393 "IPv6AcceptRA", ipv6AutoConfigEnabled);
Ravi Tejab10d8db2022-05-24 09:04:12 -05001394}
1395
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001396inline void handleDHCPPatch(
1397 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1398 const DHCPParameters& v4dhcpParms, const DHCPParameters& v6dhcpParms,
1399 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001400{
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001401 bool ipv4Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
1402 bool ipv6Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, false);
Ed Tanousbf648f72021-06-03 15:00:14 -07001403
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001404 if (ipv4Active)
1405 {
1406 updateIPv4DefaultGateway(ifaceId, "", asyncResp);
1407 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001408 bool nextv4DHCPState =
1409 v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active;
1410
1411 bool nextv6DHCPState{};
1412 if (v6dhcpParms.dhcpv6OperatingMode)
1413 {
Ravi Tejab10d8db2022-05-24 09:04:12 -05001414 if ((*v6dhcpParms.dhcpv6OperatingMode != "Enabled") &&
Ed Tanousbf648f72021-06-03 15:00:14 -07001415 (*v6dhcpParms.dhcpv6OperatingMode != "Disabled"))
1416 {
1417 messages::propertyValueFormatError(asyncResp->res,
1418 *v6dhcpParms.dhcpv6OperatingMode,
1419 "OperatingMode");
1420 return;
1421 }
Ravi Tejab10d8db2022-05-24 09:04:12 -05001422 nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Enabled");
Ed Tanousbf648f72021-06-03 15:00:14 -07001423 }
1424 else
1425 {
1426 nextv6DHCPState = ipv6Active;
1427 }
1428
Jishnu CMe4588152023-05-11 00:04:40 -05001429 bool nextDNSv4 = ethData.dnsv4Enabled;
1430 bool nextDNSv6 = ethData.dnsv6Enabled;
1431 if (v4dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001432 {
Jishnu CMe4588152023-05-11 00:04:40 -05001433 nextDNSv4 = *v4dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001434 }
Jishnu CMe4588152023-05-11 00:04:40 -05001435 if (v6dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001436 {
Jishnu CMe4588152023-05-11 00:04:40 -05001437 nextDNSv6 = *v6dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001438 }
1439
Jishnu CMe4588152023-05-11 00:04:40 -05001440 bool nextNTPv4 = ethData.ntpv4Enabled;
1441 bool nextNTPv6 = ethData.ntpv6Enabled;
1442 if (v4dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001443 {
Jishnu CMe4588152023-05-11 00:04:40 -05001444 nextNTPv4 = *v4dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001445 }
Jishnu CMe4588152023-05-11 00:04:40 -05001446 if (v6dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001447 {
Jishnu CMe4588152023-05-11 00:04:40 -05001448 nextNTPv6 = *v6dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001449 }
1450
Ravi Teja91c441e2024-02-23 09:03:43 -06001451 bool nextUsev4Domain = ethData.domainv4Enabled;
1452 bool nextUsev6Domain = ethData.domainv6Enabled;
Jishnu CMe4588152023-05-11 00:04:40 -05001453 if (v4dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001454 {
Jishnu CMe4588152023-05-11 00:04:40 -05001455 nextUsev4Domain = *v4dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001456 }
Jishnu CMe4588152023-05-11 00:04:40 -05001457 if (v6dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001458 {
Jishnu CMe4588152023-05-11 00:04:40 -05001459 nextUsev6Domain = *v6dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001460 }
1461
Ed Tanous62598e32023-07-17 17:06:25 -07001462 BMCWEB_LOG_DEBUG("set DHCPEnabled...");
Ed Tanousbf648f72021-06-03 15:00:14 -07001463 setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState,
1464 asyncResp);
Ed Tanous62598e32023-07-17 17:06:25 -07001465 BMCWEB_LOG_DEBUG("set DNSEnabled...");
Jishnu CMe4588152023-05-11 00:04:40 -05001466 setDHCPConfig("DNSEnabled", nextDNSv4, asyncResp, ifaceId,
1467 NetworkType::dhcp4);
Ed Tanous62598e32023-07-17 17:06:25 -07001468 BMCWEB_LOG_DEBUG("set NTPEnabled...");
Jishnu CMe4588152023-05-11 00:04:40 -05001469 setDHCPConfig("NTPEnabled", nextNTPv4, asyncResp, ifaceId,
1470 NetworkType::dhcp4);
Ravi Teja91c441e2024-02-23 09:03:43 -06001471 BMCWEB_LOG_DEBUG("set DomainEnabled...");
1472 setDHCPConfig("DomainEnabled", nextUsev4Domain, asyncResp, ifaceId,
Jishnu CMe4588152023-05-11 00:04:40 -05001473 NetworkType::dhcp4);
1474 BMCWEB_LOG_DEBUG("set DNSEnabled for dhcp6...");
1475 setDHCPConfig("DNSEnabled", nextDNSv6, asyncResp, ifaceId,
1476 NetworkType::dhcp6);
1477 BMCWEB_LOG_DEBUG("set NTPEnabled for dhcp6...");
1478 setDHCPConfig("NTPEnabled", nextNTPv6, asyncResp, ifaceId,
1479 NetworkType::dhcp6);
Ravi Teja91c441e2024-02-23 09:03:43 -06001480 BMCWEB_LOG_DEBUG("set DomainEnabled for dhcp6...");
1481 setDHCPConfig("DomainEnabled", nextUsev6Domain, asyncResp, ifaceId,
Jishnu CMe4588152023-05-11 00:04:40 -05001482 NetworkType::dhcp6);
Ed Tanousbf648f72021-06-03 15:00:14 -07001483}
1484
Ed Tanous77179532023-02-28 10:45:28 -08001485inline std::vector<IPv4AddressData>::const_iterator getNextStaticIpEntry(
1486 const std::vector<IPv4AddressData>::const_iterator& head,
1487 const std::vector<IPv4AddressData>::const_iterator& end)
Ed Tanousbf648f72021-06-03 15:00:14 -07001488{
1489 return std::find_if(head, end, [](const IPv4AddressData& value) {
1490 return value.origin == "Static";
1491 });
1492}
1493
Ed Tanous77179532023-02-28 10:45:28 -08001494inline std::vector<IPv6AddressData>::const_iterator getNextStaticIpEntry(
1495 const std::vector<IPv6AddressData>::const_iterator& head,
1496 const std::vector<IPv6AddressData>::const_iterator& end)
Ed Tanousbf648f72021-06-03 15:00:14 -07001497{
1498 return std::find_if(head, end, [](const IPv6AddressData& value) {
1499 return value.origin == "Static";
1500 });
1501}
1502
Ed Tanous3dfed532024-03-06 14:41:27 -08001503inline void handleIPv4StaticPatch(
1504 const std::string& ifaceId,
1505 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001506 const EthernetInterfaceData& ethData,
Ed Tanous3dfed532024-03-06 14:41:27 -08001507 const std::vector<IPv4AddressData>& ipv4Data,
1508 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001509{
Ed Tanousbf648f72021-06-03 15:00:14 -07001510 unsigned entryIdx = 1;
1511 // Find the first static IP address currently active on the NIC and
1512 // match it to the first JSON element in the IPv4StaticAddresses array.
1513 // Match each subsequent JSON element to the next static IP programmed
1514 // into the NIC.
Ed Tanous77179532023-02-28 10:45:28 -08001515 std::vector<IPv4AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001516 getNextStaticIpEntry(ipv4Data.cbegin(), ipv4Data.cend());
1517
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001518 bool gatewayValueAssigned{};
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001519 bool preserveGateway{};
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001520 std::string activePath{};
1521 std::string activeGateway{};
1522 if (!ethData.defaultGateway.empty() && ethData.defaultGateway != "0.0.0.0")
1523 {
1524 // The NIC is already configured with a default gateway. Use this if
1525 // the leading entry in the PATCH is '{}', which is preserving an active
1526 // static address.
1527 activeGateway = ethData.defaultGateway;
1528 activePath = "IPv4StaticAddresses/1";
1529 gatewayValueAssigned = true;
1530 }
1531
Ed Tanous3dfed532024-03-06 14:41:27 -08001532 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1533 input)
Ed Tanousbf648f72021-06-03 15:00:14 -07001534 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001535 std::string pathString =
1536 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001537 nlohmann::json::object_t* obj =
1538 std::get_if<nlohmann::json::object_t>(&thisJson);
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001539 if (obj == nullptr)
1540 {
1541 if (nicIpEntry != ipv4Data.cend())
1542 {
1543 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001544 nicIpEntry =
1545 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001546 if (!preserveGateway && (nicIpEntry == ipv4Data.cend()))
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001547 {
1548 // All entries have been processed, and this last has
1549 // requested the IP address be deleted. No prior entry
1550 // performed an action that created or modified a
1551 // gateway. Deleting this IP address means the default
1552 // gateway entry has to be removed as well.
1553 updateIPv4DefaultGateway(ifaceId, "", asyncResp);
1554 }
1555 entryIdx++;
1556 continue;
1557 }
1558 // Received a DELETE action on an entry not assigned to the NIC
1559 messages::resourceCannotBeDeleted(asyncResp->res);
1560 return;
1561 }
1562
1563 // An Add/Modify action is requested
1564 if (!obj->empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001565 {
1566 std::optional<std::string> address;
1567 std::optional<std::string> subnetMask;
1568 std::optional<std::string> gateway;
1569
Ed Tanous3dfed532024-03-06 14:41:27 -08001570 if (!json_util::readJsonObject(*obj, asyncResp->res, "Address",
1571 address, "SubnetMask", subnetMask,
1572 "Gateway", gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001573 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001574 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001575 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001576 return;
1577 }
1578
1579 // Find the address/subnet/gateway values. Any values that are
1580 // not explicitly provided are assumed to be unmodified from the
1581 // current state of the interface. Merge existing state into the
1582 // current request.
Ed Tanousbf648f72021-06-03 15:00:14 -07001583 if (address)
1584 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001585 if (!ip_util::ipv4VerifyIpAndGetBitcount(*address))
Ed Tanousbf648f72021-06-03 15:00:14 -07001586 {
1587 messages::propertyValueFormatError(asyncResp->res, *address,
1588 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001589 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001590 }
1591 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001592 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001593 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001594 address = (nicIpEntry->address);
Ed Tanousbf648f72021-06-03 15:00:14 -07001595 }
1596 else
1597 {
1598 messages::propertyMissing(asyncResp->res,
1599 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001600 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001601 }
1602
Ed Tanouse01d0c32023-06-30 13:21:32 -07001603 uint8_t prefixLength = 0;
Ed Tanousbf648f72021-06-03 15:00:14 -07001604 if (subnetMask)
1605 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001606 if (!ip_util::ipv4VerifyIpAndGetBitcount(*subnetMask,
1607 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001608 {
1609 messages::propertyValueFormatError(
1610 asyncResp->res, *subnetMask,
1611 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001612 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001613 }
1614 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001615 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001616 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001617 if (!ip_util::ipv4VerifyIpAndGetBitcount(nicIpEntry->netmask,
1618 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001619 {
1620 messages::propertyValueFormatError(
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001621 asyncResp->res, nicIpEntry->netmask,
Ed Tanousbf648f72021-06-03 15:00:14 -07001622 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001623 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001624 }
1625 }
1626 else
1627 {
1628 messages::propertyMissing(asyncResp->res,
1629 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001630 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001631 }
1632
1633 if (gateway)
1634 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001635 if (!ip_util::ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001636 {
1637 messages::propertyValueFormatError(asyncResp->res, *gateway,
1638 pathString + "/Gateway");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001639 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001640 }
1641 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001642 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001643 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001644 gateway = nicIpEntry->gateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001645 }
1646 else
1647 {
1648 messages::propertyMissing(asyncResp->res,
1649 pathString + "/Gateway");
Ed Tanousbf648f72021-06-03 15:00:14 -07001650 return;
1651 }
1652
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001653 if (gatewayValueAssigned)
1654 {
1655 if (activeGateway != gateway)
1656 {
1657 // A NIC can only have a single active gateway value.
1658 // If any gateway in the array of static addresses
1659 // mismatch the PATCH is in error.
1660 std::string arg1 = pathString + "/Gateway";
1661 std::string arg2 = activePath + "/Gateway";
1662 messages::propertyValueConflict(asyncResp->res, arg1, arg2);
1663 return;
1664 }
1665 }
1666 else
1667 {
1668 // Capture the very first gateway value from the incoming
1669 // JSON record and use it at the default gateway.
1670 updateIPv4DefaultGateway(ifaceId, *gateway, asyncResp);
1671 activeGateway = *gateway;
1672 activePath = pathString;
1673 gatewayValueAssigned = true;
1674 }
1675
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001676 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001677 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001678 deleteAndCreateIPAddress(IpVersion::IpV4, ifaceId,
Ed Tanous77eb0152023-09-06 10:19:18 -07001679 nicIpEntry->id, prefixLength, *address,
1680 *gateway, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001681 nicIpEntry =
1682 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001683 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001684 }
1685 else
1686 {
1687 createIPv4(ifaceId, prefixLength, *gateway, *address,
1688 asyncResp);
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001689 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001690 }
1691 entryIdx++;
1692 }
1693 else
1694 {
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001695 // Received {}, do not modify this address
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001696 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001697 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001698 nicIpEntry =
1699 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001700 preserveGateway = true;
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001701 entryIdx++;
Ed Tanousbf648f72021-06-03 15:00:14 -07001702 }
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001703 else
1704 {
1705 // Requested a DO NOT MODIFY action on an entry not assigned
1706 // to the NIC
1707 messages::propertyValueFormatError(asyncResp->res, *obj,
1708 pathString);
1709 return;
1710 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001711 }
1712 }
1713}
1714
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001715inline void handleStaticNameServersPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001716 const std::string& ifaceId,
1717 const std::vector<std::string>& updatedStaticNameServers,
1718 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1719{
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001720 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301721 asyncResp, "StaticNameServers", "xyz.openbmc_project.Network",
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001722 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1723 ifaceId,
George Liu9ae226f2023-06-21 17:56:46 +08001724 "xyz.openbmc_project.Network.EthernetInterface", "StaticNameServers",
Ginu Georgee93abac2024-06-14 17:35:27 +05301725 updatedStaticNameServers);
Ed Tanousbf648f72021-06-03 15:00:14 -07001726}
1727
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001728inline void handleIPv6StaticAddressesPatch(
Ed Tanous3dfed532024-03-06 14:41:27 -08001729 const std::string& ifaceId,
1730 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Ed Tanous77179532023-02-28 10:45:28 -08001731 const std::vector<IPv6AddressData>& ipv6Data,
Ed Tanousbf648f72021-06-03 15:00:14 -07001732 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1733{
Ed Tanousbf648f72021-06-03 15:00:14 -07001734 size_t entryIdx = 1;
Ed Tanous77179532023-02-28 10:45:28 -08001735 std::vector<IPv6AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001736 getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ed Tanous3dfed532024-03-06 14:41:27 -08001737 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1738 input)
Ed Tanousbf648f72021-06-03 15:00:14 -07001739 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001740 std::string pathString =
1741 "IPv6StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001742 nlohmann::json::object_t* obj =
1743 std::get_if<nlohmann::json::object_t>(&thisJson);
1744 if (obj != nullptr && !obj->empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001745 {
1746 std::optional<std::string> address;
1747 std::optional<uint8_t> prefixLength;
Ed Tanous3dfed532024-03-06 14:41:27 -08001748 nlohmann::json::object_t thisJsonCopy = *obj;
1749 if (!json_util::readJsonObject(thisJsonCopy, asyncResp->res,
1750 "Address", address, "PrefixLength",
1751 prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001752 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001753 messages::propertyValueFormatError(asyncResp->res, thisJsonCopy,
Ed Tanousf818b042022-06-27 13:17:35 -07001754 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001755 return;
1756 }
1757
Ed Tanousbf648f72021-06-03 15:00:14 -07001758 // Find the address and prefixLength values. Any values that are
1759 // not explicitly provided are assumed to be unmodified from the
1760 // current state of the interface. Merge existing state into the
1761 // current request.
Ed Tanousd547d8d2024-03-16 18:04:41 -07001762 if (!address)
Ed Tanousbf648f72021-06-03 15:00:14 -07001763 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001764 if (nicIpEntry == ipv6Data.end())
1765 {
1766 messages::propertyMissing(asyncResp->res,
1767 pathString + "/Address");
1768 return;
1769 }
1770 address = nicIpEntry->address;
Ed Tanousbf648f72021-06-03 15:00:14 -07001771 }
1772
Ed Tanousd547d8d2024-03-16 18:04:41 -07001773 if (!prefixLength)
Ed Tanousbf648f72021-06-03 15:00:14 -07001774 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001775 if (nicIpEntry == ipv6Data.end())
1776 {
1777 messages::propertyMissing(asyncResp->res,
1778 pathString + "/PrefixLength");
1779 return;
1780 }
1781 prefixLength = nicIpEntry->prefixLength;
Ed Tanousbf648f72021-06-03 15:00:14 -07001782 }
1783
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001784 if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001785 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001786 deleteAndCreateIPAddress(IpVersion::IpV6, ifaceId,
Ed Tanousd547d8d2024-03-16 18:04:41 -07001787 nicIpEntry->id, *prefixLength,
1788 *address, "", asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001789 nicIpEntry =
1790 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001791 }
1792 else
1793 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001794 createIPv6(ifaceId, *prefixLength, *address, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001795 }
1796 entryIdx++;
1797 }
1798 else
1799 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001800 if (nicIpEntry == ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001801 {
1802 // Requesting a DELETE/DO NOT MODIFY action for an item
1803 // that isn't present on the eth(n) interface. Input JSON is
1804 // in error, so bail out.
Ed Tanous3dfed532024-03-06 14:41:27 -08001805 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001806 {
1807 messages::resourceCannotBeDeleted(asyncResp->res);
1808 return;
1809 }
Ed Tanous3dfed532024-03-06 14:41:27 -08001810 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001811 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001812 return;
1813 }
1814
Ed Tanous3dfed532024-03-06 14:41:27 -08001815 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001816 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001817 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001818 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001819 if (nicIpEntry != ipv6Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001820 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001821 nicIpEntry =
1822 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001823 }
1824 entryIdx++;
1825 }
1826 }
1827}
1828
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001829inline std::string extractParentInterfaceName(const std::string& ifaceId)
1830{
1831 std::size_t pos = ifaceId.find('_');
1832 return ifaceId.substr(0, pos);
1833}
1834
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001835inline void parseInterfaceData(
1836 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1837 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1838 const std::vector<IPv4AddressData>& ipv4Data,
1839 const std::vector<IPv6AddressData>& ipv6Data,
1840 const std::vector<StaticGatewayData>& ipv6GatewayData)
Ed Tanousbf648f72021-06-03 15:00:14 -07001841{
Ed Tanousbf648f72021-06-03 15:00:14 -07001842 nlohmann::json& jsonResponse = asyncResp->res.jsonValue;
1843 jsonResponse["Id"] = ifaceId;
Ed Tanous253f11b2024-05-16 09:38:31 -07001844 jsonResponse["@odata.id"] =
1845 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
1846 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceId);
Ed Tanousbf648f72021-06-03 15:00:14 -07001847 jsonResponse["InterfaceEnabled"] = ethData.nicEnabled;
1848
Ed Tanousbf648f72021-06-03 15:00:14 -07001849 if (ethData.nicEnabled)
1850 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001851 jsonResponse["LinkStatus"] =
1852 ethData.linkUp ? ethernet_interface::LinkStatus::LinkUp
1853 : ethernet_interface::LinkStatus::LinkDown;
1854 jsonResponse["Status"]["State"] = resource::State::Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001855 }
1856 else
1857 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001858 jsonResponse["LinkStatus"] = ethernet_interface::LinkStatus::NoLink;
1859 jsonResponse["Status"]["State"] = resource::State::Disabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001860 }
1861
Ed Tanousbf648f72021-06-03 15:00:14 -07001862 jsonResponse["SpeedMbps"] = ethData.speed;
Tejas Patil35fb5312021-09-20 15:35:20 +05301863 jsonResponse["MTUSize"] = ethData.mtuSize;
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001864 jsonResponse["MACAddress"] = ethData.macAddress;
Ed Tanousbf648f72021-06-03 15:00:14 -07001865 jsonResponse["DHCPv4"]["DHCPEnabled"] =
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001866 translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
Jishnu CMe4588152023-05-11 00:04:40 -05001867 jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.ntpv4Enabled;
1868 jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.dnsv4Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001869 jsonResponse["DHCPv4"]["UseDomainName"] = ethData.domainv4Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001870 jsonResponse["DHCPv6"]["OperatingMode"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001871 translateDhcpEnabledToBool(ethData.dhcpEnabled, false)
1872 ? "Enabled"
1873 : "Disabled";
Jishnu CMe4588152023-05-11 00:04:40 -05001874 jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.ntpv6Enabled;
1875 jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.dnsv6Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001876 jsonResponse["DHCPv6"]["UseDomainName"] = ethData.domainv6Enabled;
Ravi Tejab10d8db2022-05-24 09:04:12 -05001877 jsonResponse["StatelessAddressAutoConfig"]["IPv6AutoConfigEnabled"] =
1878 ethData.ipv6AcceptRa;
Ed Tanousbf648f72021-06-03 15:00:14 -07001879
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001880 if (!ethData.hostName.empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001881 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001882 jsonResponse["HostName"] = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001883
1884 // When domain name is empty then it means, that it is a network
1885 // without domain names, and the host name itself must be treated as
1886 // FQDN
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001887 std::string fqdn = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001888 if (!ethData.domainnames.empty())
1889 {
1890 fqdn += "." + ethData.domainnames[0];
1891 }
1892 jsonResponse["FQDN"] = fqdn;
1893 }
1894
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001895 if (ethData.vlanId)
1896 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001897 jsonResponse["EthernetInterfaceType"] =
1898 ethernet_interface::EthernetDeviceType::Virtual;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001899 jsonResponse["VLAN"]["VLANEnable"] = true;
1900 jsonResponse["VLAN"]["VLANId"] = *ethData.vlanId;
1901 jsonResponse["VLAN"]["Tagged"] = true;
1902
1903 nlohmann::json::array_t relatedInterfaces;
1904 nlohmann::json& parentInterface = relatedInterfaces.emplace_back();
1905 parentInterface["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001906 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces",
1907 BMCWEB_REDFISH_MANAGER_URI_NAME,
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001908 extractParentInterfaceName(ifaceId));
1909 jsonResponse["Links"]["RelatedInterfaces"] =
1910 std::move(relatedInterfaces);
1911 }
1912 else
1913 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001914 jsonResponse["EthernetInterfaceType"] =
1915 ethernet_interface::EthernetDeviceType::Physical;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001916 }
1917
Ed Tanousbf648f72021-06-03 15:00:14 -07001918 jsonResponse["NameServers"] = ethData.nameServers;
1919 jsonResponse["StaticNameServers"] = ethData.staticNameServers;
1920
1921 nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"];
1922 nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"];
1923 ipv4Array = nlohmann::json::array();
1924 ipv4StaticArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001925 for (const auto& ipv4Config : ipv4Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001926 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001927 std::string gatewayStr = ipv4Config.gateway;
1928 if (gatewayStr.empty())
1929 {
1930 gatewayStr = "0.0.0.0";
1931 }
Ed Tanous14766872022-03-15 10:44:42 -07001932 nlohmann::json::object_t ipv4;
1933 ipv4["AddressOrigin"] = ipv4Config.origin;
1934 ipv4["SubnetMask"] = ipv4Config.netmask;
1935 ipv4["Address"] = ipv4Config.address;
1936 ipv4["Gateway"] = gatewayStr;
Ed Tanousbf648f72021-06-03 15:00:14 -07001937
Ed Tanousbf648f72021-06-03 15:00:14 -07001938 if (ipv4Config.origin == "Static")
1939 {
Ed Tanous14766872022-03-15 10:44:42 -07001940 ipv4StaticArray.push_back(ipv4);
Ed Tanousbf648f72021-06-03 15:00:14 -07001941 }
Ed Tanous14766872022-03-15 10:44:42 -07001942
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001943 ipv4Array.emplace_back(std::move(ipv4));
Ed Tanousbf648f72021-06-03 15:00:14 -07001944 }
1945
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001946 std::string ipv6GatewayStr = ethData.ipv6DefaultGateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001947 if (ipv6GatewayStr.empty())
1948 {
1949 ipv6GatewayStr = "0:0:0:0:0:0:0:0";
1950 }
1951
1952 jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr;
1953
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001954 nlohmann::json::array_t ipv6StaticGatewayArray;
1955 for (const auto& ipv6GatewayConfig : ipv6GatewayData)
1956 {
1957 nlohmann::json::object_t ipv6Gateway;
1958 ipv6Gateway["Address"] = ipv6GatewayConfig.gateway;
1959 ipv6Gateway["PrefixLength"] = ipv6GatewayConfig.prefixLength;
1960 ipv6StaticGatewayArray.emplace_back(std::move(ipv6Gateway));
1961 }
1962 jsonResponse["IPv6StaticDefaultGateways"] =
1963 std::move(ipv6StaticGatewayArray);
1964
Ed Tanousbf648f72021-06-03 15:00:14 -07001965 nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"];
1966 nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"];
1967 ipv6Array = nlohmann::json::array();
1968 ipv6StaticArray = nlohmann::json::array();
1969 nlohmann::json& ipv6AddrPolicyTable =
1970 jsonResponse["IPv6AddressPolicyTable"];
1971 ipv6AddrPolicyTable = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001972 for (const auto& ipv6Config : ipv6Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001973 {
Ed Tanous14766872022-03-15 10:44:42 -07001974 nlohmann::json::object_t ipv6;
1975 ipv6["Address"] = ipv6Config.address;
1976 ipv6["PrefixLength"] = ipv6Config.prefixLength;
1977 ipv6["AddressOrigin"] = ipv6Config.origin;
Sunitha Harishf8361272023-03-16 03:23:59 -05001978
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001979 ipv6Array.emplace_back(std::move(ipv6));
Ed Tanousbf648f72021-06-03 15:00:14 -07001980 if (ipv6Config.origin == "Static")
1981 {
Ed Tanous14766872022-03-15 10:44:42 -07001982 nlohmann::json::object_t ipv6Static;
1983 ipv6Static["Address"] = ipv6Config.address;
1984 ipv6Static["PrefixLength"] = ipv6Config.prefixLength;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001985 ipv6StaticArray.emplace_back(std::move(ipv6Static));
Ed Tanousbf648f72021-06-03 15:00:14 -07001986 }
1987 }
1988}
1989
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08001990inline void afterDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1991 const std::string& ifaceId,
1992 const boost::system::error_code& ec,
1993 const sdbusplus::message_t& m)
1994{
1995 if (!ec)
1996 {
1997 return;
1998 }
1999 const sd_bus_error* dbusError = m.get_error();
2000 if (dbusError == nullptr)
2001 {
2002 messages::internalError(asyncResp->res);
2003 return;
2004 }
Ed Tanous62598e32023-07-17 17:06:25 -07002005 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002006
2007 if (std::string_view("org.freedesktop.DBus.Error.UnknownObject") ==
2008 dbusError->name)
2009 {
2010 messages::resourceNotFound(asyncResp->res, "EthernetInterface",
2011 ifaceId);
2012 return;
2013 }
2014 if (std::string_view("org.freedesktop.DBus.Error.UnknownMethod") ==
2015 dbusError->name)
2016 {
2017 messages::resourceCannotBeDeleted(asyncResp->res);
2018 return;
2019 }
2020 messages::internalError(asyncResp->res);
2021}
2022
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002023inline void afterVlanCreate(
2024 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2025 const std::string& parentInterfaceUri, const std::string& vlanInterface,
2026 const boost::system::error_code& ec, const sdbusplus::message_t& m
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002027
2028)
2029{
2030 if (ec)
2031 {
2032 const sd_bus_error* dbusError = m.get_error();
2033 if (dbusError == nullptr)
2034 {
2035 messages::internalError(asyncResp->res);
2036 return;
2037 }
Ed Tanous62598e32023-07-17 17:06:25 -07002038 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002039
2040 if (std::string_view(
2041 "xyz.openbmc_project.Common.Error.ResourceNotFound") ==
2042 dbusError->name)
2043 {
2044 messages::propertyValueNotInList(
2045 asyncResp->res, parentInterfaceUri,
2046 "Links/RelatedInterfaces/0/@odata.id");
2047 return;
2048 }
2049 if (std::string_view(
2050 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
2051 dbusError->name)
2052 {
2053 messages::resourceAlreadyExists(asyncResp->res, "EthernetInterface",
2054 "Id", vlanInterface);
2055 return;
2056 }
2057 messages::internalError(asyncResp->res);
2058 return;
2059 }
2060
Ed Tanous253f11b2024-05-16 09:38:31 -07002061 const boost::urls::url vlanInterfaceUri =
2062 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2063 BMCWEB_REDFISH_MANAGER_URI_NAME, vlanInterface);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002064 asyncResp->res.addHeader("Location", vlanInterfaceUri.buffer());
2065}
2066
Ed Tanousbf648f72021-06-03 15:00:14 -07002067inline void requestEthernetInterfacesRoutes(App& app)
2068{
Ed Tanous253f11b2024-05-16 09:38:31 -07002069 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Ed Tanoused398212021-06-09 17:05:54 -07002070 .privileges(redfish::privileges::getEthernetInterfaceCollection)
Ed Tanous14766872022-03-15 10:44:42 -07002071 .methods(boost::beast::http::verb::get)(
2072 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002073 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2074 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002075 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2076 {
2077 return;
2078 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002079
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002080 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2081 {
2082 messages::resourceNotFound(asyncResp->res, "Manager",
2083 managerId);
2084 return;
2085 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002086
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002087 asyncResp->res.jsonValue["@odata.type"] =
2088 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
2089 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2090 "/redfish/v1/Managers/{}/EthernetInterfaces",
2091 BMCWEB_REDFISH_MANAGER_URI_NAME);
2092 asyncResp->res.jsonValue["Name"] =
2093 "Ethernet Network Interface Collection";
2094 asyncResp->res.jsonValue["Description"] =
2095 "Collection of EthernetInterfaces for this Manager";
2096
2097 // Get eth interface list, and call the below callback for JSON
2098 // preparation
2099 getEthernetIfaceList(
2100 [asyncResp](const bool& success,
2101 const std::vector<std::string>& ifaceList) {
2102 if (!success)
2103 {
2104 messages::internalError(asyncResp->res);
2105 return;
2106 }
2107
2108 nlohmann::json& ifaceArray =
2109 asyncResp->res.jsonValue["Members"];
2110 ifaceArray = nlohmann::json::array();
2111 for (const std::string& ifaceItem : ifaceList)
2112 {
2113 nlohmann::json::object_t iface;
2114 iface["@odata.id"] = boost::urls::format(
2115 "/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2116 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceItem);
2117 ifaceArray.push_back(std::move(iface));
2118 }
2119
2120 asyncResp->res.jsonValue["Members@odata.count"] =
2121 ifaceArray.size();
2122 asyncResp->res.jsonValue["@odata.id"] =
2123 boost::urls::format(
2124 "/redfish/v1/Managers/{}/EthernetInterfaces",
Ed Tanous253f11b2024-05-16 09:38:31 -07002125 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002126 });
2127 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002128
Ed Tanous253f11b2024-05-16 09:38:31 -07002129 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002130 .privileges(redfish::privileges::postEthernetInterfaceCollection)
2131 .methods(boost::beast::http::verb::post)(
2132 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2134 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002135 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2136 {
2137 return;
2138 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002139
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002140 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2141 {
2142 messages::resourceNotFound(asyncResp->res, "Manager",
2143 managerId);
2144 return;
2145 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002146
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002147 bool vlanEnable = false;
2148 uint32_t vlanId = 0;
2149 std::vector<nlohmann::json::object_t> relatedInterfaces;
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002150
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002151 if (!json_util::readJsonPatch(
2152 req, asyncResp->res, "VLAN/VLANEnable", vlanEnable,
2153 "VLAN/VLANId", vlanId, "Links/RelatedInterfaces",
2154 relatedInterfaces))
2155 {
2156 return;
2157 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002158
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002159 if (relatedInterfaces.size() != 1)
2160 {
2161 messages::arraySizeTooLong(asyncResp->res,
2162 "Links/RelatedInterfaces",
2163 relatedInterfaces.size());
2164 return;
2165 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002166
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002167 std::string parentInterfaceUri;
2168 if (!json_util::readJsonObject(relatedInterfaces[0],
2169 asyncResp->res, "@odata.id",
2170 parentInterfaceUri))
2171 {
2172 messages::propertyMissing(
2173 asyncResp->res, "Links/RelatedInterfaces/0/@odata.id");
2174 return;
2175 }
2176 BMCWEB_LOG_INFO("Parent Interface URI: {}", parentInterfaceUri);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002177
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002178 boost::system::result<boost::urls::url_view> parsedUri =
2179 boost::urls::parse_relative_ref(parentInterfaceUri);
2180 if (!parsedUri)
2181 {
2182 messages::propertyValueFormatError(
2183 asyncResp->res, parentInterfaceUri,
2184 "Links/RelatedInterfaces/0/@odata.id");
2185 return;
2186 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002187
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002188 std::string parentInterface;
2189 if (!crow::utility::readUrlSegments(
2190 *parsedUri, "redfish", "v1", "Managers", "bmc",
2191 "EthernetInterfaces", std::ref(parentInterface)))
2192 {
2193 messages::propertyValueNotInList(
2194 asyncResp->res, parentInterfaceUri,
2195 "Links/RelatedInterfaces/0/@odata.id");
2196 return;
2197 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002198
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002199 if (!vlanEnable)
2200 {
2201 // In OpenBMC implementation, VLANEnable cannot be false on
2202 // create
2203 messages::propertyValueIncorrect(
2204 asyncResp->res, "VLAN/VLANEnable", "false");
2205 return;
2206 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002207
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002208 std::string vlanInterface =
2209 parentInterface + "_" + std::to_string(vlanId);
2210 crow::connections::systemBus->async_method_call(
2211 [asyncResp, parentInterfaceUri,
2212 vlanInterface](const boost::system::error_code& ec,
2213 const sdbusplus::message_t& m) {
2214 afterVlanCreate(asyncResp, parentInterfaceUri,
2215 vlanInterface, ec, m);
2216 },
2217 "xyz.openbmc_project.Network",
2218 "/xyz/openbmc_project/network",
2219 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
2220 parentInterface, vlanId);
2221 });
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002222
Ed Tanous253f11b2024-05-16 09:38:31 -07002223 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002224 .privileges(redfish::privileges::getEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002225 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002226 [&app](const crow::Request& req,
2227 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002228 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002229 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2230 {
2231 return;
2232 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002233
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002234 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2235 {
2236 messages::resourceNotFound(asyncResp->res, "Manager",
2237 managerId);
2238 return;
2239 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002240
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002241 getEthernetIfaceData(
2242 ifaceId,
2243 [asyncResp, ifaceId](
2244 const bool& success,
2245 const EthernetInterfaceData& ethData,
2246 const std::vector<IPv4AddressData>& ipv4Data,
2247 const std::vector<IPv6AddressData>& ipv6Data,
2248 const std::vector<StaticGatewayData>& ipv6GatewayData) {
2249 if (!success)
2250 {
2251 // TODO(Pawel)consider distinguish between non
2252 // existing object, and other errors
2253 messages::resourceNotFound(
2254 asyncResp->res, "EthernetInterface", ifaceId);
2255 return;
2256 }
Johnathan Mantey01784822019-06-18 12:44:21 -07002257
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002258 asyncResp->res.jsonValue["@odata.type"] =
2259 "#EthernetInterface.v1_9_0.EthernetInterface";
2260 asyncResp->res.jsonValue["Name"] =
2261 "Manager Ethernet Interface";
2262 asyncResp->res.jsonValue["Description"] =
2263 "Management Network Interface";
Ratan Guptaf476acb2019-03-02 16:46:57 +05302264
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002265 parseInterfaceData(asyncResp, ifaceId, ethData,
2266 ipv4Data, ipv6Data, ipv6GatewayData);
2267 });
2268 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002269
Ed Tanous253f11b2024-05-16 09:38:31 -07002270 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002271 .privileges(redfish::privileges::patchEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002272 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002273 [&app](const crow::Request& req,
2274 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002275 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002276 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2277 {
2278 return;
2279 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002280
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002281 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2282 {
2283 messages::resourceNotFound(asyncResp->res, "Manager",
2284 managerId);
2285 return;
2286 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002287
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002288 std::optional<std::string> hostname;
2289 std::optional<std::string> fqdn;
2290 std::optional<std::string> macAddress;
2291 std::optional<std::string> ipv6DefaultGateway;
2292 std::optional<std::vector<
2293 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2294 ipv4StaticAddresses;
2295 std::optional<std::vector<
2296 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2297 ipv6StaticAddresses;
2298 std::optional<std::vector<
2299 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2300 ipv6StaticDefaultGateways;
2301 std::optional<std::vector<std::string>> staticNameServers;
2302 std::optional<bool> ipv6AutoConfigEnabled;
2303 std::optional<bool> interfaceEnabled;
2304 std::optional<size_t> mtuSize;
2305 DHCPParameters v4dhcpParms;
2306 DHCPParameters v6dhcpParms;
2307 // clang-format off
Ed Tanous3dfed532024-03-06 14:41:27 -08002308 if (!json_util::readJsonPatch(req, asyncResp->res,
2309 "DHCPv4/DHCPEnabled", v4dhcpParms.dhcpv4Enabled,
2310 "DHCPv4/UseDNSServers", v4dhcpParms.useDnsServers,
2311 "DHCPv4/UseDomainName", v4dhcpParms.useDomainName,
2312 "DHCPv4/UseNTPServers", v4dhcpParms.useNtpServers,
2313 "DHCPv6/OperatingMode", v6dhcpParms.dhcpv6OperatingMode,
2314 "DHCPv6/UseDNSServers", v6dhcpParms.useDnsServers,
2315 "DHCPv6/UseDomainName", v6dhcpParms.useDomainName,
2316 "DHCPv6/UseNTPServers", v6dhcpParms.useNtpServers,
Ravi Tejab10d8db2022-05-24 09:04:12 -05002317 "FQDN", fqdn,
2318 "HostName", hostname,
2319 "IPv4StaticAddresses", ipv4StaticAddresses,
2320 "IPv6DefaultGateway", ipv6DefaultGateway,
2321 "IPv6StaticAddresses", ipv6StaticAddresses,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05002322 "IPv6StaticDefaultGateways", ipv6StaticDefaultGateways,
Ravi Tejab10d8db2022-05-24 09:04:12 -05002323 "InterfaceEnabled", interfaceEnabled,
2324 "MACAddress", macAddress,
2325 "MTUSize", mtuSize,
2326 "StatelessAddressAutoConfig/IPv6AutoConfigEnabled", ipv6AutoConfigEnabled,
2327 "StaticNameServers", staticNameServers
2328 )
2329 )
Ed Tanous002d39b2022-05-31 08:59:27 -07002330 {
2331 return;
2332 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002333 // clang-format on
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002334
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002335 // Get single eth interface data, and call the below callback
2336 // for JSON preparation
2337 getEthernetIfaceData(
2338 ifaceId,
2339 [asyncResp, ifaceId, hostname = std::move(hostname),
2340 fqdn = std::move(fqdn), macAddress = std::move(macAddress),
2341 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
2342 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
2343 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
2344 ipv6StaticDefaultGateway =
2345 std::move(ipv6StaticDefaultGateways),
2346 staticNameServers = std::move(staticNameServers), mtuSize,
2347 ipv6AutoConfigEnabled,
2348 v4dhcpParms = std::move(v4dhcpParms),
2349 v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled](
2350 const bool success,
2351 const EthernetInterfaceData& ethData,
2352 const std::vector<IPv4AddressData>& ipv4Data,
2353 const std::vector<IPv6AddressData>& ipv6Data,
2354 const std::vector<StaticGatewayData>&
2355 ipv6GatewayData) mutable {
2356 if (!success)
2357 {
2358 // ... otherwise return error
2359 // TODO(Pawel)consider distinguish between non
2360 // existing object, and other errors
2361 messages::resourceNotFound(
2362 asyncResp->res, "EthernetInterface", ifaceId);
2363 return;
2364 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002365
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002366 handleDHCPPatch(ifaceId, ethData, v4dhcpParms,
2367 v6dhcpParms, asyncResp);
Tejas Patil35fb5312021-09-20 15:35:20 +05302368
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002369 if (hostname)
2370 {
2371 handleHostnamePatch(*hostname, asyncResp);
2372 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002373
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002374 if (ipv6AutoConfigEnabled)
2375 {
2376 handleSLAACAutoConfigPatch(
2377 ifaceId, *ipv6AutoConfigEnabled, asyncResp);
2378 }
Ravi Tejab10d8db2022-05-24 09:04:12 -05002379
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002380 if (fqdn)
2381 {
2382 handleFqdnPatch(ifaceId, *fqdn, asyncResp);
2383 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002384
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002385 if (macAddress)
2386 {
2387 handleMACAddressPatch(ifaceId, *macAddress,
2388 asyncResp);
2389 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002390
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002391 if (ipv4StaticAddresses)
2392 {
2393 handleIPv4StaticPatch(ifaceId, *ipv4StaticAddresses,
2394 ethData, ipv4Data, asyncResp);
2395 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002396
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002397 if (staticNameServers)
2398 {
2399 handleStaticNameServersPatch(
2400 ifaceId, *staticNameServers, asyncResp);
2401 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002402
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002403 if (ipv6DefaultGateway)
2404 {
2405 messages::propertyNotWritable(asyncResp->res,
2406 "IPv6DefaultGateway");
2407 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002408
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002409 if (ipv6StaticAddresses)
2410 {
2411 handleIPv6StaticAddressesPatch(ifaceId,
2412 *ipv6StaticAddresses,
2413 ipv6Data, asyncResp);
2414 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002415
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002416 if (ipv6StaticDefaultGateway)
2417 {
2418 handleIPv6DefaultGateway(
2419 ifaceId, *ipv6StaticDefaultGateway,
2420 ipv6GatewayData, asyncResp);
2421 }
Sunitha Harishce73d5c2023-04-07 06:46:49 -05002422
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002423 if (interfaceEnabled)
2424 {
2425 setDbusProperty(
2426 asyncResp, "InterfaceEnabled",
Ginu Georgee93abac2024-06-14 17:35:27 +05302427 "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08002428 sdbusplus::message::object_path(
2429 "/xyz/openbmc_project/network") /
2430 ifaceId,
2431 "xyz.openbmc_project.Network.EthernetInterface",
Ginu Georgee93abac2024-06-14 17:35:27 +05302432 "NICEnabled", *interfaceEnabled);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002433 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002434
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002435 if (mtuSize)
2436 {
2437 handleMTUSizePatch(ifaceId, *mtuSize, asyncResp);
2438 }
2439 });
2440 });
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002441
Ed Tanous253f11b2024-05-16 09:38:31 -07002442 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002443 .privileges(redfish::privileges::deleteEthernetInterface)
2444 .methods(boost::beast::http::verb::delete_)(
2445 [&app](const crow::Request& req,
2446 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002447 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002448 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2449 {
2450 return;
2451 }
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002452
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002453 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2454 {
2455 messages::resourceNotFound(asyncResp->res, "Manager",
2456 managerId);
2457 return;
2458 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002459
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002460 crow::connections::systemBus->async_method_call(
2461 [asyncResp, ifaceId](const boost::system::error_code& ec,
2462 const sdbusplus::message_t& m) {
2463 afterDelete(asyncResp, ifaceId, ec, m);
2464 },
2465 "xyz.openbmc_project.Network",
2466 std::string("/xyz/openbmc_project/network/") + ifaceId,
2467 "xyz.openbmc_project.Object.Delete", "Delete");
2468 });
Ed Tanousbf648f72021-06-03 15:00:14 -07002469}
2470
Ed Tanous1abe55e2018-09-05 08:30:59 -07002471} // namespace redfish