blob: 95632901afb3dba7ad6e5dfebe7e6baca37cb0df [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"
22#include "health.hpp"
23#include "query.hpp"
24#include "registries/privilege_registry.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070025#include "utils/ip_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/json_utils.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070027
Ed Tanous11ba3972022-07-11 09:50:41 -070028#include <boost/algorithm/string/classification.hpp>
29#include <boost/algorithm/string/split.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070030#include <boost/container/flat_set.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
George Liu7a1dbc42022-12-07 16:03:22 +080032#include <array>
Ed Tanousa24526d2018-12-10 15:17:59 -080033#include <optional>
Joshi-Mansiab6554f2020-03-10 18:33:36 +053034#include <regex>
George Liu7a1dbc42022-12-07 16:03:22 +080035#include <string_view>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010036
Ed Tanous1abe55e2018-09-05 08:30:59 -070037namespace redfish
38{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010039
Ed Tanous4a0cb852018-10-15 07:55:04 -070040enum class LinkType
41{
42 Local,
43 Global
44};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010045
46/**
47 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010048 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070049struct IPv4AddressData
50{
51 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070052 std::string address;
53 std::string domain;
54 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 std::string netmask;
56 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070057 LinkType linktype;
Sunitha Harish01c6e852020-03-20 05:04:09 -050058 bool isActive;
Ed Tanous4a0cb852018-10-15 07:55:04 -070059
Gunnar Mills1214b7e2020-06-04 10:11:30 -050060 bool operator<(const IPv4AddressData& obj) const
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070062 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010064};
65
66/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050067 * Structure for keeping IPv6 data required by Redfish
68 */
69struct IPv6AddressData
70{
71 std::string id;
72 std::string address;
73 std::string origin;
74 uint8_t prefixLength;
75
Gunnar Mills1214b7e2020-06-04 10:11:30 -050076 bool operator<(const IPv6AddressData& obj) const
Ravi Tejae48c0fc2019-04-16 08:37:20 -050077 {
78 return id < obj.id;
79 }
80};
81/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010082 * Structure for keeping basic single Ethernet Interface information
83 * available from DBus
84 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070085struct EthernetInterfaceData
86{
Ed Tanous4a0cb852018-10-15 07:55:04 -070087 uint32_t speed;
Tejas Patil35fb5312021-09-20 15:35:20 +053088 size_t mtuSize;
Jiaqing Zhao82695a52022-04-14 15:15:59 +080089 bool autoNeg;
90 bool dnsEnabled;
91 bool ntpEnabled;
92 bool hostNameEnabled;
Johnathan Manteyaa05fb22020-01-08 12:08:44 -080093 bool linkUp;
Johnathan Manteyeeedda22019-10-29 16:09:52 -070094 bool nicEnabled;
Jiaqing Zhao82695a52022-04-14 15:15:59 +080095 std::string dhcpEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -070096 std::string operatingMode;
Jiaqing Zhao82695a52022-04-14 15:15:59 +080097 std::string hostName;
98 std::string defaultGateway;
99 std::string ipv6DefaultGateway;
100 std::string macAddress;
Jiaqing Zhao17e22022022-04-14 18:58:06 +0800101 std::optional<uint32_t> vlanId;
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500102 std::vector<std::string> nameServers;
103 std::vector<std::string> staticNameServers;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800104 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100105};
106
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700107struct DHCPParameters
108{
109 std::optional<bool> dhcpv4Enabled;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800110 std::optional<bool> useDnsServers;
111 std::optional<bool> useNtpServers;
112 std::optional<bool> useDomainName;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700113 std::optional<std::string> dhcpv6OperatingMode;
114};
115
Ed Tanous4a0cb852018-10-15 07:55:04 -0700116// Helper function that changes bits netmask notation (i.e. /24)
117// into full dot notation
118inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700120 uint32_t value = 0xffffffff << (32 - bits);
121 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
122 std::to_string((value >> 16) & 0xff) + "." +
123 std::to_string((value >> 8) & 0xff) + "." +
124 std::to_string(value & 0xff);
125 return netmask;
126}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100127
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800128inline bool translateDhcpEnabledToBool(const std::string& inputDHCP,
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700129 bool isIPv4)
130{
131 if (isIPv4)
132 {
133 return (
134 (inputDHCP ==
135 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4") ||
136 (inputDHCP ==
137 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
138 }
139 return ((inputDHCP ==
140 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6") ||
141 (inputDHCP ==
142 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
143}
144
Ed Tanous2c70f802020-09-28 14:29:23 -0700145inline std::string getDhcpEnabledEnumeration(bool isIPv4, bool isIPv6)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700146{
147 if (isIPv4 && isIPv6)
148 {
149 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both";
150 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700151 if (isIPv4)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700152 {
153 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4";
154 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700155 if (isIPv6)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700156 {
157 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6";
158 }
159 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.none";
160}
161
Ed Tanous4a0cb852018-10-15 07:55:04 -0700162inline std::string
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 translateAddressOriginDbusToRedfish(const std::string& inputOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700164 bool isIPv4)
165{
166 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700168 return "Static";
169 }
170 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
171 {
172 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700174 return "IPv4LinkLocal";
175 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700176 return "LinkLocal";
Ed Tanous4a0cb852018-10-15 07:55:04 -0700177 }
178 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
179 {
180 if (isIPv4)
181 {
182 return "DHCP";
183 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700184 return "DHCPv6";
Ed Tanous4a0cb852018-10-15 07:55:04 -0700185 }
186 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
187 {
188 return "SLAAC";
189 }
190 return "";
191}
192
Ed Tanous02cad962022-06-30 16:50:15 -0700193inline bool extractEthernetInterfaceData(
194 const std::string& ethifaceId,
195 const dbus::utility::ManagedObjectType& dbusData,
196 EthernetInterfaceData& ethData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700197{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700198 bool idFound = false;
Ed Tanous02cad962022-06-30 16:50:15 -0700199 for (const auto& objpath : dbusData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700200 {
Ed Tanous02cad962022-06-30 16:50:15 -0700201 for (const auto& ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700202 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000203 if (objpath.first == "/xyz/openbmc_project/network/" + ethifaceId)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700204 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700205 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700206 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700207 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 for (const auto& propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700210 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700211 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500212 const std::string* mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800213 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700214 if (mac != nullptr)
215 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800216 ethData.macAddress = *mac;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700217 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700219 }
220 }
221 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
222 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500223 for (const auto& propertyPair : ifacePair.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700224 {
225 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700226 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227 const uint32_t* id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800228 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700229 if (id != nullptr)
230 {
Jiaqing Zhao17e22022022-04-14 18:58:06 +0800231 ethData.vlanId = *id;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700232 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700234 }
235 }
236 else if (ifacePair.first ==
237 "xyz.openbmc_project.Network.EthernetInterface")
238 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239 for (const auto& propertyPair : ifacePair.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700240 {
241 if (propertyPair.first == "AutoNeg")
242 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700243 const bool* autoNeg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800244 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700245 if (autoNeg != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700246 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800247 ethData.autoNeg = *autoNeg;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700248 }
249 }
250 else if (propertyPair.first == "Speed")
251 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252 const uint32_t* speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800253 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700254 if (speed != nullptr)
255 {
256 ethData.speed = *speed;
257 }
258 }
Tejas Patil35fb5312021-09-20 15:35:20 +0530259 else if (propertyPair.first == "MTU")
260 {
261 const uint32_t* mtuSize =
262 std::get_if<uint32_t>(&propertyPair.second);
263 if (mtuSize != nullptr)
264 {
265 ethData.mtuSize = *mtuSize;
266 }
267 }
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800268 else if (propertyPair.first == "LinkUp")
269 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 const bool* linkUp =
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800271 std::get_if<bool>(&propertyPair.second);
272 if (linkUp != nullptr)
273 {
274 ethData.linkUp = *linkUp;
275 }
276 }
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700277 else if (propertyPair.first == "NICEnabled")
278 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500279 const bool* nicEnabled =
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700280 std::get_if<bool>(&propertyPair.second);
281 if (nicEnabled != nullptr)
282 {
283 ethData.nicEnabled = *nicEnabled;
284 }
285 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500286 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700287 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500288 const std::vector<std::string>* nameservers =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500289 std::get_if<std::vector<std::string>>(
Ed Tanous029573d2019-02-01 10:57:49 -0800290 &propertyPair.second);
291 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700292 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700293 ethData.nameServers = *nameservers;
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500294 }
295 }
296 else if (propertyPair.first == "StaticNameServers")
297 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500298 const std::vector<std::string>* staticNameServers =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500299 std::get_if<std::vector<std::string>>(
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500300 &propertyPair.second);
301 if (staticNameServers != nullptr)
302 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700303 ethData.staticNameServers = *staticNameServers;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700304 }
305 }
manojkiraneda2a133282019-02-19 13:09:43 +0530306 else if (propertyPair.first == "DHCPEnabled")
307 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700308 const std::string* dhcpEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700309 std::get_if<std::string>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700310 if (dhcpEnabled != nullptr)
manojkiraneda2a133282019-02-19 13:09:43 +0530311 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800312 ethData.dhcpEnabled = *dhcpEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +0530313 }
314 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800315 else if (propertyPair.first == "DomainName")
316 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500317 const std::vector<std::string>* domainNames =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500318 std::get_if<std::vector<std::string>>(
Jennifer Leed24bfc72019-03-05 13:03:37 -0800319 &propertyPair.second);
320 if (domainNames != nullptr)
321 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700322 ethData.domainnames = *domainNames;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800323 }
324 }
Ravi Teja9010ec22019-08-01 23:30:25 -0500325 else if (propertyPair.first == "DefaultGateway")
326 {
327 const std::string* defaultGateway =
328 std::get_if<std::string>(&propertyPair.second);
329 if (defaultGateway != nullptr)
330 {
331 std::string defaultGatewayStr = *defaultGateway;
332 if (defaultGatewayStr.empty())
333 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800334 ethData.defaultGateway = "0.0.0.0";
Ravi Teja9010ec22019-08-01 23:30:25 -0500335 }
336 else
337 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800338 ethData.defaultGateway = defaultGatewayStr;
Ravi Teja9010ec22019-08-01 23:30:25 -0500339 }
340 }
341 }
342 else if (propertyPair.first == "DefaultGateway6")
343 {
344 const std::string* defaultGateway6 =
345 std::get_if<std::string>(&propertyPair.second);
346 if (defaultGateway6 != nullptr)
347 {
348 std::string defaultGateway6Str =
349 *defaultGateway6;
350 if (defaultGateway6Str.empty())
351 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800352 ethData.ipv6DefaultGateway =
Ravi Teja9010ec22019-08-01 23:30:25 -0500353 "0:0:0:0:0:0:0:0";
354 }
355 else
356 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800357 ethData.ipv6DefaultGateway =
Ravi Teja9010ec22019-08-01 23:30:25 -0500358 defaultGateway6Str;
359 }
360 }
361 }
Ed Tanous029573d2019-02-01 10:57:49 -0800362 }
363 }
364 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700365
Jian Zhang1e3f85e2022-12-13 13:50:35 +0800366 if (objpath.first == "/xyz/openbmc_project/network/dhcp")
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700367 {
368 if (ifacePair.first ==
369 "xyz.openbmc_project.Network.DHCPConfiguration")
370 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500371 for (const auto& propertyPair : ifacePair.second)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700372 {
373 if (propertyPair.first == "DNSEnabled")
374 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700375 const bool* dnsEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700376 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700377 if (dnsEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700378 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800379 ethData.dnsEnabled = *dnsEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700380 }
381 }
382 else if (propertyPair.first == "NTPEnabled")
383 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700384 const bool* ntpEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700385 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700386 if (ntpEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700387 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800388 ethData.ntpEnabled = *ntpEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700389 }
390 }
391 else if (propertyPair.first == "HostNameEnabled")
392 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700393 const bool* hostNameEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700394 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700395 if (hostNameEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700396 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800397 ethData.hostNameEnabled = *hostNameEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700398 }
399 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700400 }
401 }
402 }
Ed Tanous029573d2019-02-01 10:57:49 -0800403 // System configuration shows up in the global namespace, so no need
404 // to check eth number
405 if (ifacePair.first ==
406 "xyz.openbmc_project.Network.SystemConfiguration")
407 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500408 for (const auto& propertyPair : ifacePair.second)
Ed Tanous029573d2019-02-01 10:57:49 -0800409 {
410 if (propertyPair.first == "HostName")
411 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500412 const std::string* hostname =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500413 std::get_if<std::string>(&propertyPair.second);
Ed Tanous029573d2019-02-01 10:57:49 -0800414 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700415 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800416 ethData.hostName = *hostname;
Ed Tanous029573d2019-02-01 10:57:49 -0800417 }
418 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 }
420 }
421 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700423 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700424}
425
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500426// Helper function that extracts data for single ethernet ipv6 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700427inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000428 extractIPV6Data(const std::string& ethifaceId,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800429 const dbus::utility::ManagedObjectType& dbusData,
Ed Tanous81ce6092020-12-17 16:54:55 +0000430 boost::container::flat_set<IPv6AddressData>& ipv6Config)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500431{
Tony Lee353163e2022-11-23 11:06:10 +0800432 const std::string ipPathStart =
433 "/xyz/openbmc_project/network/" + ethifaceId;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500434
435 // Since there might be several IPv6 configurations aligned with
436 // single ethernet interface, loop over all of them
Ed Tanous81ce6092020-12-17 16:54:55 +0000437 for (const auto& objpath : dbusData)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500438 {
439 // Check if proper pattern for object path appears
Tony Lee353163e2022-11-23 11:06:10 +0800440 if (objpath.first.str.starts_with(ipPathStart + "/"))
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500441 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800442 for (const auto& interface : objpath.second)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500443 {
444 if (interface.first == "xyz.openbmc_project.Network.IP")
445 {
Tony Lee353163e2022-11-23 11:06:10 +0800446 auto type = std::find_if(interface.second.begin(),
447 interface.second.end(),
448 [](const auto& property) {
449 return property.first == "Type";
450 });
451 if (type == interface.second.end())
452 {
453 continue;
454 }
455
456 const std::string* typeStr =
457 std::get_if<std::string>(&type->second);
458
459 if (typeStr == nullptr ||
460 (*typeStr !=
461 "xyz.openbmc_project.Network.IP.Protocol.IPv6"))
462 {
463 continue;
464 }
465
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500466 // Instance IPv6AddressData structure, and set as
467 // appropriate
468 std::pair<
469 boost::container::flat_set<IPv6AddressData>::iterator,
470 bool>
Ed Tanous81ce6092020-12-17 16:54:55 +0000471 it = ipv6Config.insert(IPv6AddressData{});
Ed Tanous2c70f802020-09-28 14:29:23 -0700472 IPv6AddressData& ipv6Address = *it.first;
473 ipv6Address.id =
Tony Lee353163e2022-11-23 11:06:10 +0800474 objpath.first.str.substr(ipPathStart.size());
Ed Tanous9eb808c2022-01-25 10:19:23 -0800475 for (const auto& property : interface.second)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500476 {
477 if (property.first == "Address")
478 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500479 const std::string* address =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500480 std::get_if<std::string>(&property.second);
481 if (address != nullptr)
482 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700483 ipv6Address.address = *address;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500484 }
485 }
486 else if (property.first == "Origin")
487 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500488 const std::string* origin =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500489 std::get_if<std::string>(&property.second);
490 if (origin != nullptr)
491 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700492 ipv6Address.origin =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500493 translateAddressOriginDbusToRedfish(*origin,
494 false);
495 }
496 }
497 else if (property.first == "PrefixLength")
498 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500499 const uint8_t* prefix =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500500 std::get_if<uint8_t>(&property.second);
501 if (prefix != nullptr)
502 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700503 ipv6Address.prefixLength = *prefix;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500504 }
505 }
Asmitha Karunanithi889ff692021-11-29 08:43:30 -0600506 else if (property.first == "Type" ||
507 property.first == "Gateway")
508 {
509 // Type & Gateway is not used
510 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500511 else
512 {
513 BMCWEB_LOG_ERROR
514 << "Got extra property: " << property.first
515 << " on the " << objpath.first.str << " object";
516 }
517 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500518 }
519 }
520 }
521 }
522}
523
Ed Tanous4a0cb852018-10-15 07:55:04 -0700524// Helper function that extracts data for single ethernet ipv4 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700525inline void
Ed Tanous81ce6092020-12-17 16:54:55 +0000526 extractIPData(const std::string& ethifaceId,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800527 const dbus::utility::ManagedObjectType& dbusData,
Ed Tanous81ce6092020-12-17 16:54:55 +0000528 boost::container::flat_set<IPv4AddressData>& ipv4Config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700529{
Tony Lee353163e2022-11-23 11:06:10 +0800530 const std::string ipPathStart =
531 "/xyz/openbmc_project/network/" + ethifaceId;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700532
533 // Since there might be several IPv4 configurations aligned with
534 // single ethernet interface, loop over all of them
Ed Tanous81ce6092020-12-17 16:54:55 +0000535 for (const auto& objpath : dbusData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700536 {
537 // Check if proper pattern for object path appears
Tony Lee353163e2022-11-23 11:06:10 +0800538 if (objpath.first.str.starts_with(ipPathStart + "/"))
Ed Tanous4a0cb852018-10-15 07:55:04 -0700539 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800540 for (const auto& interface : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700541 {
542 if (interface.first == "xyz.openbmc_project.Network.IP")
543 {
Tony Lee353163e2022-11-23 11:06:10 +0800544 auto type = std::find_if(interface.second.begin(),
545 interface.second.end(),
546 [](const auto& property) {
547 return property.first == "Type";
548 });
549 if (type == interface.second.end())
550 {
551 continue;
552 }
553
554 const std::string* typeStr =
555 std::get_if<std::string>(&type->second);
556
557 if (typeStr == nullptr ||
558 (*typeStr !=
559 "xyz.openbmc_project.Network.IP.Protocol.IPv4"))
560 {
561 continue;
562 }
563
Ed Tanous4a0cb852018-10-15 07:55:04 -0700564 // Instance IPv4AddressData structure, and set as
565 // appropriate
566 std::pair<
567 boost::container::flat_set<IPv4AddressData>::iterator,
568 bool>
Ed Tanous81ce6092020-12-17 16:54:55 +0000569 it = ipv4Config.insert(IPv4AddressData{});
Ed Tanous2c70f802020-09-28 14:29:23 -0700570 IPv4AddressData& ipv4Address = *it.first;
571 ipv4Address.id =
Tony Lee353163e2022-11-23 11:06:10 +0800572 objpath.first.str.substr(ipPathStart.size());
Ed Tanous9eb808c2022-01-25 10:19:23 -0800573 for (const auto& property : interface.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700574 {
575 if (property.first == "Address")
576 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500577 const std::string* address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800578 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700579 if (address != nullptr)
580 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700581 ipv4Address.address = *address;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700582 }
583 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700584 else if (property.first == "Origin")
585 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500586 const std::string* origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800587 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700588 if (origin != nullptr)
589 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700590 ipv4Address.origin =
Ed Tanous4a0cb852018-10-15 07:55:04 -0700591 translateAddressOriginDbusToRedfish(*origin,
592 true);
593 }
594 }
595 else if (property.first == "PrefixLength")
596 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500597 const uint8_t* mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800598 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700599 if (mask != nullptr)
600 {
601 // convert it to the string
Ed Tanous2c70f802020-09-28 14:29:23 -0700602 ipv4Address.netmask = getNetmask(*mask);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700603 }
604 }
Asmitha Karunanithi889ff692021-11-29 08:43:30 -0600605 else if (property.first == "Type" ||
606 property.first == "Gateway")
607 {
608 // Type & Gateway is not used
609 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700610 else
611 {
612 BMCWEB_LOG_ERROR
613 << "Got extra property: " << property.first
614 << " on the " << objpath.first.str << " object";
615 }
616 }
617 // Check if given address is local, or global
Ed Tanous2c70f802020-09-28 14:29:23 -0700618 ipv4Address.linktype =
Ed Tanous11ba3972022-07-11 09:50:41 -0700619 ipv4Address.address.starts_with("169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700620 ? LinkType::Local
621 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700622 }
623 }
624 }
625 }
626}
627
628/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700629 * @brief Deletes given IPv4 interface
Ed Tanous4a0cb852018-10-15 07:55:04 -0700630 *
631 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700632 * @param[in] ipHash DBus Hash id of IP that should be deleted
633 * @param[io] asyncResp Response object that will be returned to client
634 *
635 * @return None
636 */
Ravi Teja9c5e5852023-02-26 21:33:52 -0600637inline void deleteIPAddress(const std::string& ifaceId,
638 const std::string& ipHash,
639 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700640{
641 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800642 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700643 if (ec)
644 {
645 messages::internalError(asyncResp->res);
646 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700647 },
648 "xyz.openbmc_project.Network",
Ravi Teja9c5e5852023-02-26 21:33:52 -0600649 "/xyz/openbmc_project/network/" + ifaceId + ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700650 "xyz.openbmc_project.Object.Delete", "Delete");
651}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652
Gunnar Mills244b6d52021-04-12 15:44:23 -0500653inline void updateIPv4DefaultGateway(
654 const std::string& ifaceId, const std::string& gateway,
655 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ravi Teja9010ec22019-08-01 23:30:25 -0500656{
657 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800658 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 if (ec)
660 {
661 messages::internalError(asyncResp->res);
662 return;
663 }
664 asyncResp->res.result(boost::beast::http::status::no_content);
Ravi Teja9010ec22019-08-01 23:30:25 -0500665 },
666 "xyz.openbmc_project.Network",
667 "/xyz/openbmc_project/network/" + ifaceId,
668 "org.freedesktop.DBus.Properties", "Set",
669 "xyz.openbmc_project.Network.EthernetInterface", "DefaultGateway",
Ed Tanous168e20c2021-12-13 14:39:53 -0800670 dbus::utility::DbusVariantType(gateway));
Ravi Teja9010ec22019-08-01 23:30:25 -0500671}
Ed Tanous4a0cb852018-10-15 07:55:04 -0700672/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700673 * @brief Creates a static IPv4 entry
Ed Tanous4a0cb852018-10-15 07:55:04 -0700674 *
Johnathan Mantey01784822019-06-18 12:44:21 -0700675 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
676 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
677 * @param[in] gateway IPv4 address of this interfaces gateway
678 * @param[in] address IPv4 address to assign to this interface
679 * @param[io] asyncResp Response object that will be returned to client
Ed Tanous4a0cb852018-10-15 07:55:04 -0700680 *
681 * @return None
682 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000683inline void createIPv4(const std::string& ifaceId, uint8_t prefixLength,
684 const std::string& gateway, const std::string& address,
zhanghch058d1b46d2021-04-01 11:18:24 +0800685 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700686{
Ed Tanous002d39b2022-05-31 08:59:27 -0700687 auto createIpHandler =
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800688 [asyncResp, ifaceId, gateway](const boost::system::error_code& ec) {
Ravi Teja9010ec22019-08-01 23:30:25 -0500689 if (ec)
690 {
691 messages::internalError(asyncResp->res);
692 return;
693 }
694 updateIPv4DefaultGateway(ifaceId, gateway, asyncResp);
695 };
696
Ed Tanous4a0cb852018-10-15 07:55:04 -0700697 crow::connections::systemBus->async_method_call(
Ravi Teja9010ec22019-08-01 23:30:25 -0500698 std::move(createIpHandler), "xyz.openbmc_project.Network",
Ed Tanous4a0cb852018-10-15 07:55:04 -0700699 "/xyz/openbmc_project/network/" + ifaceId,
700 "xyz.openbmc_project.Network.IP.Create", "IP",
Johnathan Mantey01784822019-06-18 12:44:21 -0700701 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, prefixLength,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700702 gateway);
703}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500704
705/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700706 * @brief Deletes the IPv6 entry for this interface and creates a replacement
707 * static IPv6 entry
708 *
709 * @param[in] ifaceId Id of interface upon which to create the IPv6 entry
710 * @param[in] id The unique hash entry identifying the DBus entry
711 * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
712 * @param[in] address IPv6 address to assign to this interface
713 * @param[io] asyncResp Response object that will be returned to client
714 *
715 * @return None
716 */
Ravi Teja9c5e5852023-02-26 21:33:52 -0600717
718enum class IpVersion
719{
720 IpV4,
721 IpV6
722};
723
724inline void deleteAndCreateIPAddress(
725 IpVersion version, const std::string& ifaceId, const std::string& id,
726 uint8_t prefixLength, const std::string& address,
727 const std::string& gateway,
728 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Johnathan Mantey01784822019-06-18 12:44:21 -0700729{
730 crow::connections::systemBus->async_method_call(
Ravi Teja9c5e5852023-02-26 21:33:52 -0600731 [asyncResp, version, ifaceId, address, prefixLength,
732 gateway](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700733 if (ec)
734 {
735 messages::internalError(asyncResp->res);
736 }
Ravi Teja9c5e5852023-02-26 21:33:52 -0600737 std::string protocol = "xyz.openbmc_project.Network.IP.Protocol.";
738 protocol += version == IpVersion::IpV4 ? "IPv4" : "IPv6";
Ed Tanous002d39b2022-05-31 08:59:27 -0700739 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800740 [asyncResp](const boost::system::error_code& ec2) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700741 if (ec2)
Johnathan Mantey01784822019-06-18 12:44:21 -0700742 {
743 messages::internalError(asyncResp->res);
744 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 },
746 "xyz.openbmc_project.Network",
747 "/xyz/openbmc_project/network/" + ifaceId,
Ravi Teja9c5e5852023-02-26 21:33:52 -0600748 "xyz.openbmc_project.Network.IP.Create", "IP", protocol, address,
749 prefixLength, gateway);
Johnathan Mantey01784822019-06-18 12:44:21 -0700750 },
751 "xyz.openbmc_project.Network",
Ravi Teja9c5e5852023-02-26 21:33:52 -0600752 "/xyz/openbmc_project/network/" + ifaceId + id,
Johnathan Mantey01784822019-06-18 12:44:21 -0700753 "xyz.openbmc_project.Object.Delete", "Delete");
754}
755
756/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500757 * @brief Creates IPv6 with given data
758 *
759 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500760 * @param[in] prefixLength Prefix length that needs to be added
761 * @param[in] address IP address that needs to be added
762 * @param[io] asyncResp Response object that will be returned to client
763 *
764 * @return None
765 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500766inline void createIPv6(const std::string& ifaceId, uint8_t prefixLength,
767 const std::string& address,
zhanghch058d1b46d2021-04-01 11:18:24 +0800768 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500769{
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800770 auto createIpHandler = [asyncResp](const boost::system::error_code& ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500771 if (ec)
772 {
773 messages::internalError(asyncResp->res);
774 }
775 };
776 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
Gunnar Mills4e0453b2020-07-08 14:00:30 -0500777 // does not have associated gateway property
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500778 crow::connections::systemBus->async_method_call(
779 std::move(createIpHandler), "xyz.openbmc_project.Network",
780 "/xyz/openbmc_project/network/" + ifaceId,
781 "xyz.openbmc_project.Network.IP.Create", "IP",
782 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
783 "");
784}
785
Ed Tanous4a0cb852018-10-15 07:55:04 -0700786/**
787 * Function that retrieves all properties for given Ethernet Interface
788 * Object
789 * from EntityManager Network Manager
790 * @param ethiface_id a eth interface id to query on DBus
791 * @param callback a function that shall be called to convert Dbus output
792 * into JSON
793 */
794template <typename CallbackFunc>
Ed Tanous81ce6092020-12-17 16:54:55 +0000795void getEthernetIfaceData(const std::string& ethifaceId,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500796 CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700797{
George Liuf5892d02023-03-01 10:37:08 +0800798 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
799 dbus::utility::getManagedObjects(
800 "xyz.openbmc_project.Network", path,
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800801 [ethifaceId{std::string{ethifaceId}},
802 callback{std::forward<CallbackFunc>(callback)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800803 const boost::system::error_code& errorCode,
Ed Tanous02cad962022-06-30 16:50:15 -0700804 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700805 EthernetInterfaceData ethData{};
806 boost::container::flat_set<IPv4AddressData> ipv4Data;
807 boost::container::flat_set<IPv6AddressData> ipv6Data;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700808
Ed Tanous002d39b2022-05-31 08:59:27 -0700809 if (errorCode)
810 {
811 callback(false, ethData, ipv4Data, ipv6Data);
812 return;
813 }
814
815 bool found = extractEthernetInterfaceData(ethifaceId, resp, ethData);
816 if (!found)
817 {
818 callback(false, ethData, ipv4Data, ipv6Data);
819 return;
820 }
821
822 extractIPData(ethifaceId, resp, ipv4Data);
823 // Fix global GW
824 for (IPv4AddressData& ipv4 : ipv4Data)
825 {
826 if (((ipv4.linktype == LinkType::Global) &&
827 (ipv4.gateway == "0.0.0.0")) ||
828 (ipv4.origin == "DHCP") || (ipv4.origin == "Static"))
Ed Tanous4a0cb852018-10-15 07:55:04 -0700829 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700830 ipv4.gateway = ethData.defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700831 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700832 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700833
Ed Tanous002d39b2022-05-31 08:59:27 -0700834 extractIPV6Data(ethifaceId, resp, ipv6Data);
835 // Finally make a callback with useful data
836 callback(true, ethData, ipv4Data, ipv6Data);
George Liuf5892d02023-03-01 10:37:08 +0800837 });
Ed Tanous271584a2019-07-09 16:24:22 -0700838}
Ed Tanous4a0cb852018-10-15 07:55:04 -0700839
840/**
841 * Function that retrieves all Ethernet Interfaces available through Network
842 * Manager
843 * @param callback a function that shall be called to convert Dbus output
844 * into JSON.
845 */
846template <typename CallbackFunc>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500847void getEthernetIfaceList(CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700848{
George Liuf5892d02023-03-01 10:37:08 +0800849 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
850 dbus::utility::getManagedObjects(
851 "xyz.openbmc_project.Network", path,
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800852 [callback{std::forward<CallbackFunc>(callback)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800853 const boost::system::error_code& errorCode,
George Liuf5892d02023-03-01 10:37:08 +0800854 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700855 // Callback requires vector<string> to retrieve all available
856 // ethernet interfaces
857 boost::container::flat_set<std::string> ifaceList;
858 ifaceList.reserve(resp.size());
859 if (errorCode)
860 {
861 callback(false, ifaceList);
862 return;
863 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700864
Ed Tanous002d39b2022-05-31 08:59:27 -0700865 // Iterate over all retrieved ObjectPaths.
866 for (const auto& objpath : resp)
867 {
868 // And all interfaces available for certain ObjectPath.
869 for (const auto& interface : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700870 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700871 // If interface is
872 // xyz.openbmc_project.Network.EthernetInterface, this is
873 // what we're looking for.
874 if (interface.first ==
875 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700876 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700877 std::string ifaceId = objpath.first.filename();
878 if (ifaceId.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700880 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700882 // and put it into output vector.
883 ifaceList.emplace(ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700885 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700886 }
887 // Finally make a callback with useful data
888 callback(true, ifaceList);
George Liuf5892d02023-03-01 10:37:08 +0800889 });
Ed Tanous271584a2019-07-09 16:24:22 -0700890}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100891
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700892inline void
893 handleHostnamePatch(const std::string& hostname,
894 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895{
Ed Tanousbf648f72021-06-03 15:00:14 -0700896 // SHOULD handle host names of up to 255 characters(RFC 1123)
897 if (hostname.length() > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 {
Ed Tanousbf648f72021-06-03 15:00:14 -0700899 messages::propertyValueFormatError(asyncResp->res, hostname,
900 "HostName");
901 return;
902 }
903 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800904 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700905 if (ec)
906 {
907 messages::internalError(asyncResp->res);
908 }
Ed Tanousbf648f72021-06-03 15:00:14 -0700909 },
910 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network/config",
911 "org.freedesktop.DBus.Properties", "Set",
912 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800913 dbus::utility::DbusVariantType(hostname));
Ed Tanousbf648f72021-06-03 15:00:14 -0700914}
915
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700916inline void
Tejas Patil35fb5312021-09-20 15:35:20 +0530917 handleMTUSizePatch(const std::string& ifaceId, const size_t mtuSize,
918 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
919{
920 sdbusplus::message::object_path objPath =
921 "/xyz/openbmc_project/network/" + ifaceId;
922 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800923 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700924 if (ec)
925 {
926 messages::internalError(asyncResp->res);
927 }
Tejas Patil35fb5312021-09-20 15:35:20 +0530928 },
929 "xyz.openbmc_project.Network", objPath,
930 "org.freedesktop.DBus.Properties", "Set",
931 "xyz.openbmc_project.Network.EthernetInterface", "MTU",
932 std::variant<size_t>(mtuSize));
933}
934
935inline void
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700936 handleDomainnamePatch(const std::string& ifaceId,
937 const std::string& domainname,
938 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -0700939{
940 std::vector<std::string> vectorDomainname = {domainname};
941 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800942 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700943 if (ec)
944 {
945 messages::internalError(asyncResp->res);
946 }
Ed Tanousbf648f72021-06-03 15:00:14 -0700947 },
948 "xyz.openbmc_project.Network",
949 "/xyz/openbmc_project/network/" + ifaceId,
950 "org.freedesktop.DBus.Properties", "Set",
951 "xyz.openbmc_project.Network.EthernetInterface", "DomainName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800952 dbus::utility::DbusVariantType(vectorDomainname));
Ed Tanousbf648f72021-06-03 15:00:14 -0700953}
954
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700955inline bool isHostnameValid(const std::string& hostname)
Ed Tanousbf648f72021-06-03 15:00:14 -0700956{
957 // A valid host name can never have the dotted-decimal form (RFC 1123)
958 if (std::all_of(hostname.begin(), hostname.end(), ::isdigit))
959 {
960 return false;
961 }
962 // Each label(hostname/subdomains) within a valid FQDN
963 // MUST handle host names of up to 63 characters (RFC 1123)
964 // labels cannot start or end with hyphens (RFC 952)
965 // labels can start with numbers (RFC 1123)
966 const std::regex pattern(
967 "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$");
968
969 return std::regex_match(hostname, pattern);
970}
971
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700972inline bool isDomainnameValid(const std::string& domainname)
Ed Tanousbf648f72021-06-03 15:00:14 -0700973{
974 // Can have multiple subdomains
975 // Top Level Domain's min length is 2 character
George Liu0fda0f12021-11-16 10:06:17 +0800976 const std::regex pattern(
977 "^([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 -0700978
979 return std::regex_match(domainname, pattern);
980}
981
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700982inline void handleFqdnPatch(const std::string& ifaceId, const std::string& fqdn,
983 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -0700984{
985 // Total length of FQDN must not exceed 255 characters(RFC 1035)
986 if (fqdn.length() > 255)
987 {
988 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
989 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700990 }
991
Ed Tanousbf648f72021-06-03 15:00:14 -0700992 size_t pos = fqdn.find('.');
993 if (pos == std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994 {
Ed Tanousbf648f72021-06-03 15:00:14 -0700995 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
996 return;
997 }
zhanghch058d1b46d2021-04-01 11:18:24 +0800998
Ed Tanousbf648f72021-06-03 15:00:14 -0700999 std::string hostname;
1000 std::string domainname;
1001 domainname = (fqdn).substr(pos + 1);
1002 hostname = (fqdn).substr(0, pos);
1003
1004 if (!isHostnameValid(hostname) || !isDomainnameValid(domainname))
1005 {
1006 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1007 return;
1008 }
1009
1010 handleHostnamePatch(hostname, asyncResp);
1011 handleDomainnamePatch(ifaceId, domainname, asyncResp);
1012}
1013
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001014inline void
1015 handleMACAddressPatch(const std::string& ifaceId,
1016 const std::string& macAddress,
1017 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001018{
Johnathan Mantey58283f42022-08-15 14:38:36 -07001019 static constexpr std::string_view dbusNotAllowedError =
1020 "xyz.openbmc_project.Common.Error.NotAllowed";
1021
Ed Tanousbf648f72021-06-03 15:00:14 -07001022 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001023 [asyncResp, macAddress](const boost::system::error_code& ec,
Patrick Williams5b378542022-11-26 09:41:59 -06001024 const sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001025 if (ec)
1026 {
Johnathan Mantey58283f42022-08-15 14:38:36 -07001027 const sd_bus_error* err = msg.get_error();
1028 if (err == nullptr)
1029 {
1030 messages::internalError(asyncResp->res);
1031 return;
1032 }
1033 if (err->name == dbusNotAllowedError)
1034 {
1035 messages::propertyNotWritable(asyncResp->res, "MACAddress");
1036 return;
1037 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001038 messages::internalError(asyncResp->res);
1039 return;
1040 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001041 },
1042 "xyz.openbmc_project.Network",
1043 "/xyz/openbmc_project/network/" + ifaceId,
1044 "org.freedesktop.DBus.Properties", "Set",
1045 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
Ed Tanous168e20c2021-12-13 14:39:53 -08001046 dbus::utility::DbusVariantType(macAddress));
Ed Tanousbf648f72021-06-03 15:00:14 -07001047}
1048
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001049inline void setDHCPEnabled(const std::string& ifaceId,
1050 const std::string& propertyName, const bool v4Value,
1051 const bool v6Value,
1052 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001053{
1054 const std::string dhcp = getDhcpEnabledEnumeration(v4Value, v6Value);
1055 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001056 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001057 if (ec)
1058 {
1059 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1060 messages::internalError(asyncResp->res);
1061 return;
1062 }
1063 messages::success(asyncResp->res);
Ed Tanousbf648f72021-06-03 15:00:14 -07001064 },
1065 "xyz.openbmc_project.Network",
1066 "/xyz/openbmc_project/network/" + ifaceId,
1067 "org.freedesktop.DBus.Properties", "Set",
1068 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
Ed Tanous168e20c2021-12-13 14:39:53 -08001069 dbus::utility::DbusVariantType{dhcp});
Ed Tanousbf648f72021-06-03 15:00:14 -07001070}
1071
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001072inline void setEthernetInterfaceBoolProperty(
Ed Tanousbf648f72021-06-03 15:00:14 -07001073 const std::string& ifaceId, const std::string& propertyName,
1074 const bool& value, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1075{
1076 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001077 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001078 if (ec)
1079 {
1080 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1081 messages::internalError(asyncResp->res);
1082 return;
1083 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001084 },
1085 "xyz.openbmc_project.Network",
1086 "/xyz/openbmc_project/network/" + ifaceId,
1087 "org.freedesktop.DBus.Properties", "Set",
1088 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
Ed Tanous168e20c2021-12-13 14:39:53 -08001089 dbus::utility::DbusVariantType{value});
Ed Tanousbf648f72021-06-03 15:00:14 -07001090}
1091
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001092inline void setDHCPv4Config(const std::string& propertyName, const bool& value,
1093 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001094{
1095 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1096 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001097 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001098 if (ec)
1099 {
1100 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1101 messages::internalError(asyncResp->res);
1102 return;
1103 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001104 },
Jian Zhang1e3f85e2022-12-13 13:50:35 +08001105 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network/dhcp",
Ed Tanousbf648f72021-06-03 15:00:14 -07001106 "org.freedesktop.DBus.Properties", "Set",
1107 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
Ed Tanous168e20c2021-12-13 14:39:53 -08001108 dbus::utility::DbusVariantType{value});
Ed Tanousbf648f72021-06-03 15:00:14 -07001109}
1110
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001111inline void handleDHCPPatch(const std::string& ifaceId,
1112 const EthernetInterfaceData& ethData,
1113 const DHCPParameters& v4dhcpParms,
1114 const DHCPParameters& v6dhcpParms,
1115 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001116{
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001117 bool ipv4Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
1118 bool ipv6Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, false);
Ed Tanousbf648f72021-06-03 15:00:14 -07001119
1120 bool nextv4DHCPState =
1121 v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active;
1122
1123 bool nextv6DHCPState{};
1124 if (v6dhcpParms.dhcpv6OperatingMode)
1125 {
1126 if ((*v6dhcpParms.dhcpv6OperatingMode != "Stateful") &&
1127 (*v6dhcpParms.dhcpv6OperatingMode != "Stateless") &&
1128 (*v6dhcpParms.dhcpv6OperatingMode != "Disabled"))
1129 {
1130 messages::propertyValueFormatError(asyncResp->res,
1131 *v6dhcpParms.dhcpv6OperatingMode,
1132 "OperatingMode");
1133 return;
1134 }
1135 nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Stateful");
1136 }
1137 else
1138 {
1139 nextv6DHCPState = ipv6Active;
1140 }
1141
1142 bool nextDNS{};
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001143 if (v4dhcpParms.useDnsServers && v6dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001144 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001145 if (*v4dhcpParms.useDnsServers != *v6dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001146 {
1147 messages::generalError(asyncResp->res);
1148 return;
1149 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001150 nextDNS = *v4dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001151 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001152 else if (v4dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001153 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001154 nextDNS = *v4dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001155 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001156 else if (v6dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001157 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001158 nextDNS = *v6dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001159 }
1160 else
1161 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001162 nextDNS = ethData.dnsEnabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001163 }
1164
1165 bool nextNTP{};
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001166 if (v4dhcpParms.useNtpServers && v6dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001167 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001168 if (*v4dhcpParms.useNtpServers != *v6dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001169 {
1170 messages::generalError(asyncResp->res);
1171 return;
1172 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001173 nextNTP = *v4dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001174 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001175 else if (v4dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001176 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001177 nextNTP = *v4dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001178 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001179 else if (v6dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001180 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001181 nextNTP = *v6dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001182 }
1183 else
1184 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001185 nextNTP = ethData.ntpEnabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001186 }
1187
1188 bool nextUseDomain{};
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001189 if (v4dhcpParms.useDomainName && v6dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001190 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001191 if (*v4dhcpParms.useDomainName != *v6dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001192 {
1193 messages::generalError(asyncResp->res);
1194 return;
1195 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001196 nextUseDomain = *v4dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001197 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001198 else if (v4dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001199 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001200 nextUseDomain = *v4dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001201 }
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001202 else if (v6dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001203 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001204 nextUseDomain = *v6dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001205 }
1206 else
1207 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001208 nextUseDomain = ethData.hostNameEnabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001209 }
1210
1211 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1212 setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState,
1213 asyncResp);
1214 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1215 setDHCPv4Config("DNSEnabled", nextDNS, asyncResp);
1216 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1217 setDHCPv4Config("NTPEnabled", nextNTP, asyncResp);
1218 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1219 setDHCPv4Config("HostNameEnabled", nextUseDomain, asyncResp);
1220}
1221
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001222inline boost::container::flat_set<IPv4AddressData>::const_iterator
Ed Tanousbf648f72021-06-03 15:00:14 -07001223 getNextStaticIpEntry(
1224 const boost::container::flat_set<IPv4AddressData>::const_iterator& head,
1225 const boost::container::flat_set<IPv4AddressData>::const_iterator& end)
1226{
1227 return std::find_if(head, end, [](const IPv4AddressData& value) {
1228 return value.origin == "Static";
1229 });
1230}
1231
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001232inline boost::container::flat_set<IPv6AddressData>::const_iterator
Ed Tanousbf648f72021-06-03 15:00:14 -07001233 getNextStaticIpEntry(
1234 const boost::container::flat_set<IPv6AddressData>::const_iterator& head,
1235 const boost::container::flat_set<IPv6AddressData>::const_iterator& end)
1236{
1237 return std::find_if(head, end, [](const IPv6AddressData& value) {
1238 return value.origin == "Static";
1239 });
1240}
1241
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001242inline void handleIPv4StaticPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001243 const std::string& ifaceId, nlohmann::json& input,
1244 const boost::container::flat_set<IPv4AddressData>& ipv4Data,
1245 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1246{
1247 if ((!input.is_array()) || input.empty())
1248 {
1249 messages::propertyValueTypeError(
1250 asyncResp->res,
1251 input.dump(2, ' ', true, nlohmann::json::error_handler_t::replace),
1252 "IPv4StaticAddresses");
1253 return;
1254 }
1255
1256 unsigned entryIdx = 1;
1257 // Find the first static IP address currently active on the NIC and
1258 // match it to the first JSON element in the IPv4StaticAddresses array.
1259 // Match each subsequent JSON element to the next static IP programmed
1260 // into the NIC.
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001261 boost::container::flat_set<IPv4AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001262 getNextStaticIpEntry(ipv4Data.cbegin(), ipv4Data.cend());
1263
1264 for (nlohmann::json& thisJson : input)
1265 {
1266 std::string pathString =
1267 "IPv4StaticAddresses/" + std::to_string(entryIdx);
1268
1269 if (!thisJson.is_null() && !thisJson.empty())
1270 {
1271 std::optional<std::string> address;
1272 std::optional<std::string> subnetMask;
1273 std::optional<std::string> gateway;
1274
1275 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1276 address, "SubnetMask", subnetMask,
1277 "Gateway", gateway))
1278 {
1279 messages::propertyValueFormatError(
1280 asyncResp->res,
1281 thisJson.dump(2, ' ', true,
1282 nlohmann::json::error_handler_t::replace),
1283 pathString);
1284 return;
1285 }
1286
1287 // Find the address/subnet/gateway values. Any values that are
1288 // not explicitly provided are assumed to be unmodified from the
1289 // current state of the interface. Merge existing state into the
1290 // current request.
1291 const std::string* addr = nullptr;
1292 const std::string* gw = nullptr;
1293 uint8_t prefixLength = 0;
1294 bool errorInEntry = false;
1295 if (address)
1296 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001297 if (ip_util::ipv4VerifyIpAndGetBitcount(*address))
Ed Tanousbf648f72021-06-03 15:00:14 -07001298 {
1299 addr = &(*address);
1300 }
1301 else
1302 {
1303 messages::propertyValueFormatError(asyncResp->res, *address,
1304 pathString + "/Address");
1305 errorInEntry = true;
1306 }
1307 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001308 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001309 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001310 addr = &(nicIpEntry->address);
Ed Tanousbf648f72021-06-03 15:00:14 -07001311 }
1312 else
1313 {
1314 messages::propertyMissing(asyncResp->res,
1315 pathString + "/Address");
1316 errorInEntry = true;
1317 }
1318
1319 if (subnetMask)
1320 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001321 if (!ip_util::ipv4VerifyIpAndGetBitcount(*subnetMask,
1322 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001323 {
1324 messages::propertyValueFormatError(
1325 asyncResp->res, *subnetMask,
1326 pathString + "/SubnetMask");
1327 errorInEntry = true;
1328 }
1329 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001330 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001331 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001332 if (!ip_util::ipv4VerifyIpAndGetBitcount(nicIpEntry->netmask,
1333 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001334 {
1335 messages::propertyValueFormatError(
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001336 asyncResp->res, nicIpEntry->netmask,
Ed Tanousbf648f72021-06-03 15:00:14 -07001337 pathString + "/SubnetMask");
1338 errorInEntry = true;
1339 }
1340 }
1341 else
1342 {
1343 messages::propertyMissing(asyncResp->res,
1344 pathString + "/SubnetMask");
1345 errorInEntry = true;
1346 }
1347
1348 if (gateway)
1349 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001350 if (ip_util::ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001351 {
1352 gw = &(*gateway);
1353 }
1354 else
1355 {
1356 messages::propertyValueFormatError(asyncResp->res, *gateway,
1357 pathString + "/Gateway");
1358 errorInEntry = true;
1359 }
1360 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001361 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001362 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001363 gw = &nicIpEntry->gateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001364 }
1365 else
1366 {
1367 messages::propertyMissing(asyncResp->res,
1368 pathString + "/Gateway");
1369 errorInEntry = true;
1370 }
1371
1372 if (errorInEntry)
1373 {
1374 return;
1375 }
1376
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001377 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001378 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001379 deleteAndCreateIPAddress(IpVersion::IpV4, ifaceId,
1380 nicIpEntry->id, prefixLength, *gw,
1381 *addr, asyncResp);
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001382 nicIpEntry =
1383 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001384 }
1385 else
1386 {
1387 createIPv4(ifaceId, prefixLength, *gateway, *address,
1388 asyncResp);
1389 }
1390 entryIdx++;
1391 }
1392 else
1393 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001394 if (nicIpEntry == ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001395 {
1396 // Requesting a DELETE/DO NOT MODIFY action for an item
1397 // that isn't present on the eth(n) interface. Input JSON is
1398 // in error, so bail out.
1399 if (thisJson.is_null())
1400 {
1401 messages::resourceCannotBeDeleted(asyncResp->res);
1402 return;
1403 }
1404 messages::propertyValueFormatError(
1405 asyncResp->res,
1406 thisJson.dump(2, ' ', true,
1407 nlohmann::json::error_handler_t::replace),
1408 pathString);
1409 return;
1410 }
1411
1412 if (thisJson.is_null())
1413 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001414 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001415 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001416 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001417 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001418 nicIpEntry =
1419 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001420 }
1421 entryIdx++;
1422 }
1423 }
1424}
1425
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001426inline void handleStaticNameServersPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001427 const std::string& ifaceId,
1428 const std::vector<std::string>& updatedStaticNameServers,
1429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1430{
1431 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001432 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001433 if (ec)
1434 {
1435 messages::internalError(asyncResp->res);
1436 return;
1437 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001438 },
1439 "xyz.openbmc_project.Network",
1440 "/xyz/openbmc_project/network/" + ifaceId,
1441 "org.freedesktop.DBus.Properties", "Set",
1442 "xyz.openbmc_project.Network.EthernetInterface", "StaticNameServers",
Ed Tanous168e20c2021-12-13 14:39:53 -08001443 dbus::utility::DbusVariantType{updatedStaticNameServers});
Ed Tanousbf648f72021-06-03 15:00:14 -07001444}
1445
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001446inline void handleIPv6StaticAddressesPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001447 const std::string& ifaceId, const nlohmann::json& input,
1448 const boost::container::flat_set<IPv6AddressData>& ipv6Data,
1449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1450{
1451 if (!input.is_array() || input.empty())
1452 {
1453 messages::propertyValueTypeError(
1454 asyncResp->res,
1455 input.dump(2, ' ', true, nlohmann::json::error_handler_t::replace),
1456 "IPv6StaticAddresses");
1457 return;
1458 }
1459 size_t entryIdx = 1;
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001460 boost::container::flat_set<IPv6AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001461 getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend());
1462 for (const nlohmann::json& thisJson : input)
1463 {
1464 std::string pathString =
1465 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1466
1467 if (!thisJson.is_null() && !thisJson.empty())
1468 {
1469 std::optional<std::string> address;
1470 std::optional<uint8_t> prefixLength;
1471 nlohmann::json thisJsonCopy = thisJson;
1472 if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address",
1473 address, "PrefixLength", prefixLength))
1474 {
1475 messages::propertyValueFormatError(
1476 asyncResp->res,
1477 thisJson.dump(2, ' ', true,
1478 nlohmann::json::error_handler_t::replace),
1479 pathString);
1480 return;
1481 }
1482
Ed Tanous543f4402022-01-06 13:12:53 -08001483 const std::string* addr = nullptr;
1484 uint8_t prefix = 0;
Ed Tanousbf648f72021-06-03 15:00:14 -07001485
1486 // Find the address and prefixLength values. Any values that are
1487 // not explicitly provided are assumed to be unmodified from the
1488 // current state of the interface. Merge existing state into the
1489 // current request.
1490 if (address)
1491 {
1492 addr = &(*address);
1493 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001494 else if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001495 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001496 addr = &(nicIpEntry->address);
Ed Tanousbf648f72021-06-03 15:00:14 -07001497 }
1498 else
1499 {
1500 messages::propertyMissing(asyncResp->res,
1501 pathString + "/Address");
1502 return;
1503 }
1504
1505 if (prefixLength)
1506 {
1507 prefix = *prefixLength;
1508 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001509 else if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001510 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001511 prefix = nicIpEntry->prefixLength;
Ed Tanousbf648f72021-06-03 15:00:14 -07001512 }
1513 else
1514 {
1515 messages::propertyMissing(asyncResp->res,
1516 pathString + "/PrefixLength");
1517 return;
1518 }
1519
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001520 if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001521 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001522 deleteAndCreateIPAddress(IpVersion::IpV6, ifaceId,
1523 nicIpEntry->id, prefix, "", *addr,
1524 asyncResp);
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001525 nicIpEntry =
1526 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001527 }
1528 else
1529 {
1530 createIPv6(ifaceId, *prefixLength, *addr, asyncResp);
1531 }
1532 entryIdx++;
1533 }
1534 else
1535 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001536 if (nicIpEntry == ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001537 {
1538 // Requesting a DELETE/DO NOT MODIFY action for an item
1539 // that isn't present on the eth(n) interface. Input JSON is
1540 // in error, so bail out.
1541 if (thisJson.is_null())
1542 {
1543 messages::resourceCannotBeDeleted(asyncResp->res);
1544 return;
1545 }
1546 messages::propertyValueFormatError(
1547 asyncResp->res,
1548 thisJson.dump(2, ' ', true,
1549 nlohmann::json::error_handler_t::replace),
1550 pathString);
1551 return;
1552 }
1553
1554 if (thisJson.is_null())
1555 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001556 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001557 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001558 if (nicIpEntry != ipv6Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001559 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001560 nicIpEntry =
1561 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001562 }
1563 entryIdx++;
1564 }
1565 }
1566}
1567
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001568inline void parseInterfaceData(
Ed Tanousbf648f72021-06-03 15:00:14 -07001569 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1570 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1571 const boost::container::flat_set<IPv4AddressData>& ipv4Data,
1572 const boost::container::flat_set<IPv6AddressData>& ipv6Data)
1573{
George Liu7a1dbc42022-12-07 16:03:22 +08001574 constexpr std::array<std::string_view, 1> inventoryForEthernet = {
Ed Tanousbf648f72021-06-03 15:00:14 -07001575 "xyz.openbmc_project.Inventory.Item.Ethernet"};
1576
1577 nlohmann::json& jsonResponse = asyncResp->res.jsonValue;
1578 jsonResponse["Id"] = ifaceId;
Willy Tueddfc432022-09-26 16:46:38 +00001579 jsonResponse["@odata.id"] = crow::utility::urlFromPieces(
1580 "redfish", "v1", "Managers", "bmc", "EthernetInterfaces", ifaceId);
Ed Tanousbf648f72021-06-03 15:00:14 -07001581 jsonResponse["InterfaceEnabled"] = ethData.nicEnabled;
1582
1583 auto health = std::make_shared<HealthPopulate>(asyncResp);
1584
George Liu7a1dbc42022-12-07 16:03:22 +08001585 dbus::utility::getSubTreePaths(
1586 "/", 0, inventoryForEthernet,
1587 [health](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001588 const dbus::utility::MapperGetSubTreePathsResponse& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001589 if (ec)
1590 {
1591 return;
1592 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001593
Ed Tanous002d39b2022-05-31 08:59:27 -07001594 health->inventory = resp;
George Liu7a1dbc42022-12-07 16:03:22 +08001595 });
Ed Tanousbf648f72021-06-03 15:00:14 -07001596
1597 health->populate();
1598
1599 if (ethData.nicEnabled)
1600 {
Johnathan Mantey0ef0e282022-11-15 12:15:02 -08001601 jsonResponse["LinkStatus"] = ethData.linkUp ? "LinkUp" : "LinkDown";
Ed Tanousbf648f72021-06-03 15:00:14 -07001602 jsonResponse["Status"]["State"] = "Enabled";
1603 }
1604 else
1605 {
1606 jsonResponse["LinkStatus"] = "NoLink";
1607 jsonResponse["Status"]["State"] = "Disabled";
1608 }
1609
Ed Tanousbf648f72021-06-03 15:00:14 -07001610 jsonResponse["SpeedMbps"] = ethData.speed;
Tejas Patil35fb5312021-09-20 15:35:20 +05301611 jsonResponse["MTUSize"] = ethData.mtuSize;
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001612 jsonResponse["MACAddress"] = ethData.macAddress;
Ed Tanousbf648f72021-06-03 15:00:14 -07001613 jsonResponse["DHCPv4"]["DHCPEnabled"] =
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001614 translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
1615 jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.ntpEnabled;
1616 jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.dnsEnabled;
1617 jsonResponse["DHCPv4"]["UseDomainName"] = ethData.hostNameEnabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001618
1619 jsonResponse["DHCPv6"]["OperatingMode"] =
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001620 translateDhcpEnabledToBool(ethData.dhcpEnabled, false) ? "Stateful"
Ed Tanousbf648f72021-06-03 15:00:14 -07001621 : "Disabled";
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001622 jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.ntpEnabled;
1623 jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.dnsEnabled;
1624 jsonResponse["DHCPv6"]["UseDomainName"] = ethData.hostNameEnabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001625
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001626 if (!ethData.hostName.empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001627 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001628 jsonResponse["HostName"] = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001629
1630 // When domain name is empty then it means, that it is a network
1631 // without domain names, and the host name itself must be treated as
1632 // FQDN
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001633 std::string fqdn = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001634 if (!ethData.domainnames.empty())
1635 {
1636 fqdn += "." + ethData.domainnames[0];
1637 }
1638 jsonResponse["FQDN"] = fqdn;
1639 }
1640
Ed Tanous613dabe2022-07-09 11:17:36 -07001641 jsonResponse["VLANs"]["@odata.id"] =
1642 crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
1643 "EthernetInterfaces", ifaceId, "VLANs");
Ed Tanousbf648f72021-06-03 15:00:14 -07001644
1645 jsonResponse["NameServers"] = ethData.nameServers;
1646 jsonResponse["StaticNameServers"] = ethData.staticNameServers;
1647
1648 nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"];
1649 nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"];
1650 ipv4Array = nlohmann::json::array();
1651 ipv4StaticArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001652 for (const auto& ipv4Config : ipv4Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001653 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001654 std::string gatewayStr = ipv4Config.gateway;
1655 if (gatewayStr.empty())
1656 {
1657 gatewayStr = "0.0.0.0";
1658 }
Ed Tanous14766872022-03-15 10:44:42 -07001659 nlohmann::json::object_t ipv4;
1660 ipv4["AddressOrigin"] = ipv4Config.origin;
1661 ipv4["SubnetMask"] = ipv4Config.netmask;
1662 ipv4["Address"] = ipv4Config.address;
1663 ipv4["Gateway"] = gatewayStr;
Ed Tanousbf648f72021-06-03 15:00:14 -07001664
Ed Tanousbf648f72021-06-03 15:00:14 -07001665 if (ipv4Config.origin == "Static")
1666 {
Ed Tanous14766872022-03-15 10:44:42 -07001667 ipv4StaticArray.push_back(ipv4);
Ed Tanousbf648f72021-06-03 15:00:14 -07001668 }
Ed Tanous14766872022-03-15 10:44:42 -07001669
1670 ipv4Array.push_back(std::move(ipv4));
Ed Tanousbf648f72021-06-03 15:00:14 -07001671 }
1672
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001673 std::string ipv6GatewayStr = ethData.ipv6DefaultGateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001674 if (ipv6GatewayStr.empty())
1675 {
1676 ipv6GatewayStr = "0:0:0:0:0:0:0:0";
1677 }
1678
1679 jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr;
1680
1681 nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"];
1682 nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"];
1683 ipv6Array = nlohmann::json::array();
1684 ipv6StaticArray = nlohmann::json::array();
1685 nlohmann::json& ipv6AddrPolicyTable =
1686 jsonResponse["IPv6AddressPolicyTable"];
1687 ipv6AddrPolicyTable = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001688 for (const auto& ipv6Config : ipv6Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001689 {
Ed Tanous14766872022-03-15 10:44:42 -07001690 nlohmann::json::object_t ipv6;
1691 ipv6["Address"] = ipv6Config.address;
1692 ipv6["PrefixLength"] = ipv6Config.prefixLength;
1693 ipv6["AddressOrigin"] = ipv6Config.origin;
Sunitha Harishf8361272023-03-16 03:23:59 -05001694
Ed Tanous14766872022-03-15 10:44:42 -07001695 ipv6Array.push_back(std::move(ipv6));
Ed Tanousbf648f72021-06-03 15:00:14 -07001696 if (ipv6Config.origin == "Static")
1697 {
Ed Tanous14766872022-03-15 10:44:42 -07001698 nlohmann::json::object_t ipv6Static;
1699 ipv6Static["Address"] = ipv6Config.address;
1700 ipv6Static["PrefixLength"] = ipv6Config.prefixLength;
1701 ipv6StaticArray.push_back(std::move(ipv6Static));
Ed Tanousbf648f72021-06-03 15:00:14 -07001702 }
1703 }
1704}
1705
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001706inline bool verifyNames(const std::string& parent, const std::string& iface)
Ed Tanousbf648f72021-06-03 15:00:14 -07001707{
Ed Tanous11ba3972022-07-11 09:50:41 -07001708 return iface.starts_with(parent + "_");
Ed Tanousbf648f72021-06-03 15:00:14 -07001709}
1710
1711inline void requestEthernetInterfacesRoutes(App& app)
1712{
1713 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanoused398212021-06-09 17:05:54 -07001714 .privileges(redfish::privileges::getEthernetInterfaceCollection)
Ed Tanous14766872022-03-15 10:44:42 -07001715 .methods(boost::beast::http::verb::get)(
1716 [&app](const crow::Request& req,
1717 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001718 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001719 {
1720 return;
1721 }
1722
1723 asyncResp->res.jsonValue["@odata.type"] =
1724 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
1725 asyncResp->res.jsonValue["@odata.id"] =
1726 "/redfish/v1/Managers/bmc/EthernetInterfaces";
1727 asyncResp->res.jsonValue["Name"] =
1728 "Ethernet Network Interface Collection";
1729 asyncResp->res.jsonValue["Description"] =
1730 "Collection of EthernetInterfaces for this Manager";
1731
1732 // Get eth interface list, and call the below callback for JSON
1733 // preparation
1734 getEthernetIfaceList(
1735 [asyncResp](
1736 const bool& success,
1737 const boost::container::flat_set<std::string>& ifaceList) {
1738 if (!success)
1739 {
1740 messages::internalError(asyncResp->res);
1741 return;
1742 }
1743
1744 nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
1745 ifaceArray = nlohmann::json::array();
1746 std::string tag = "_";
1747 for (const std::string& ifaceItem : ifaceList)
1748 {
1749 std::size_t found = ifaceItem.find(tag);
1750 if (found == std::string::npos)
Jason M. Billsf12894f2018-10-09 12:45:45 -07001751 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001752 nlohmann::json::object_t iface;
Willy Tueddfc432022-09-26 16:46:38 +00001753 iface["@odata.id"] = crow::utility::urlFromPieces(
1754 "redfish", "v1", "Managers", "bmc",
1755 "EthernetInterfaces", ifaceItem);
Ed Tanous002d39b2022-05-31 08:59:27 -07001756 ifaceArray.push_back(std::move(iface));
Jason M. Billsf12894f2018-10-09 12:45:45 -07001757 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001758 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001759
Ed Tanous002d39b2022-05-31 08:59:27 -07001760 asyncResp->res.jsonValue["Members@odata.count"] = ifaceArray.size();
1761 asyncResp->res.jsonValue["@odata.id"] =
1762 "/redfish/v1/Managers/bmc/EthernetInterfaces";
1763 });
1764 });
Johnathan Mantey01784822019-06-18 12:44:21 -07001765
Ed Tanousbf648f72021-06-03 15:00:14 -07001766 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001767 .privileges(redfish::privileges::getEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07001768 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001769 [&app](const crow::Request& req,
1770 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1771 const std::string& ifaceId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001772 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001773 {
1774 return;
1775 }
1776 getEthernetIfaceData(
1777 ifaceId,
1778 [asyncResp, ifaceId](
1779 const bool& success, const EthernetInterfaceData& ethData,
1780 const boost::container::flat_set<IPv4AddressData>& ipv4Data,
1781 const boost::container::flat_set<IPv6AddressData>& ipv6Data) {
1782 if (!success)
1783 {
1784 // TODO(Pawel)consider distinguish between non
1785 // existing object, and other errors
1786 messages::resourceNotFound(asyncResp->res, "EthernetInterface",
1787 ifaceId);
1788 return;
1789 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001790
Jiaqing Zhao188cb622022-05-26 02:14:28 +08001791 // Keep using the v1.6.0 schema here as currently bmcweb have to use
1792 // "VLANs" property deprecated in v1.7.0 for VLAN creation/deletion.
Ed Tanous002d39b2022-05-31 08:59:27 -07001793 asyncResp->res.jsonValue["@odata.type"] =
Jiaqing Zhao188cb622022-05-26 02:14:28 +08001794 "#EthernetInterface.v1_6_0.EthernetInterface";
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1796 asyncResp->res.jsonValue["Description"] =
1797 "Management Network Interface";
Ratan Guptaf476acb2019-03-02 16:46:57 +05301798
Ed Tanous002d39b2022-05-31 08:59:27 -07001799 parseInterfaceData(asyncResp, ifaceId, ethData, ipv4Data, ipv6Data);
Ed Tanousbf648f72021-06-03 15:00:14 -07001800 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001801 });
Johnathan Mantey01784822019-06-18 12:44:21 -07001802
Ed Tanousbf648f72021-06-03 15:00:14 -07001803 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001804 .privileges(redfish::privileges::patchEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07001805 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001806 [&app](const crow::Request& req,
1807 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1808 const std::string& ifaceId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001809 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001810 {
1811 return;
1812 }
1813 std::optional<std::string> hostname;
1814 std::optional<std::string> fqdn;
1815 std::optional<std::string> macAddress;
1816 std::optional<std::string> ipv6DefaultGateway;
1817 std::optional<nlohmann::json> ipv4StaticAddresses;
1818 std::optional<nlohmann::json> ipv6StaticAddresses;
1819 std::optional<std::vector<std::string>> staticNameServers;
1820 std::optional<nlohmann::json> dhcpv4;
1821 std::optional<nlohmann::json> dhcpv6;
1822 std::optional<bool> interfaceEnabled;
1823 std::optional<size_t> mtuSize;
1824 DHCPParameters v4dhcpParms;
1825 DHCPParameters v6dhcpParms;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826
Ed Tanous002d39b2022-05-31 08:59:27 -07001827 if (!json_util::readJsonPatch(
1828 req, asyncResp->res, "HostName", hostname, "FQDN", fqdn,
1829 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1830 macAddress, "StaticNameServers", staticNameServers,
1831 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1832 ipv6StaticAddresses, "DHCPv4", dhcpv4, "DHCPv6", dhcpv6,
1833 "MTUSize", mtuSize, "InterfaceEnabled", interfaceEnabled))
1834 {
1835 return;
1836 }
1837 if (dhcpv4)
1838 {
1839 if (!json_util::readJson(*dhcpv4, asyncResp->res, "DHCPEnabled",
1840 v4dhcpParms.dhcpv4Enabled, "UseDNSServers",
1841 v4dhcpParms.useDnsServers, "UseNTPServers",
1842 v4dhcpParms.useNtpServers, "UseDomainName",
1843 v4dhcpParms.useDomainName))
1844 {
1845 return;
1846 }
1847 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001848
Ed Tanous002d39b2022-05-31 08:59:27 -07001849 if (dhcpv6)
1850 {
1851 if (!json_util::readJson(*dhcpv6, asyncResp->res, "OperatingMode",
1852 v6dhcpParms.dhcpv6OperatingMode,
1853 "UseDNSServers", v6dhcpParms.useDnsServers,
1854 "UseNTPServers", v6dhcpParms.useNtpServers,
1855 "UseDomainName",
1856 v6dhcpParms.useDomainName))
1857 {
1858 return;
1859 }
1860 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001861
Ed Tanous002d39b2022-05-31 08:59:27 -07001862 // Get single eth interface data, and call the below callback
1863 // for JSON preparation
1864 getEthernetIfaceData(
1865 ifaceId,
1866 [asyncResp, ifaceId, hostname = std::move(hostname),
1867 fqdn = std::move(fqdn), macAddress = std::move(macAddress),
1868 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
1869 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1870 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
1871 staticNameServers = std::move(staticNameServers),
Ed Tanousbc200892022-06-30 17:49:12 -07001872 dhcpv4 = std::move(dhcpv4), dhcpv6 = std::move(dhcpv6), mtuSize,
1873 v4dhcpParms = std::move(v4dhcpParms),
Ed Tanous002d39b2022-05-31 08:59:27 -07001874 v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled](
1875 const bool& success, const EthernetInterfaceData& ethData,
1876 const boost::container::flat_set<IPv4AddressData>& ipv4Data,
1877 const boost::container::flat_set<IPv6AddressData>& ipv6Data) {
1878 if (!success)
1879 {
1880 // ... otherwise return error
1881 // TODO(Pawel)consider distinguish between non
1882 // existing object, and other errors
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001883 messages::resourceNotFound(asyncResp->res, "EthernetInterface",
Ed Tanous002d39b2022-05-31 08:59:27 -07001884 ifaceId);
1885 return;
1886 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001887
Ed Tanous002d39b2022-05-31 08:59:27 -07001888 if (dhcpv4 || dhcpv6)
1889 {
1890 handleDHCPPatch(ifaceId, ethData, v4dhcpParms, v6dhcpParms,
Ed Tanousbf648f72021-06-03 15:00:14 -07001891 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001892 }
Tejas Patil35fb5312021-09-20 15:35:20 +05301893
Ed Tanous002d39b2022-05-31 08:59:27 -07001894 if (hostname)
1895 {
1896 handleHostnamePatch(*hostname, asyncResp);
1897 }
1898
1899 if (fqdn)
1900 {
1901 handleFqdnPatch(ifaceId, *fqdn, asyncResp);
1902 }
1903
1904 if (macAddress)
1905 {
1906 handleMACAddressPatch(ifaceId, *macAddress, asyncResp);
1907 }
1908
1909 if (ipv4StaticAddresses)
1910 {
1911 // TODO(ed) for some reason the capture of
1912 // ipv4Addresses above is returning a const value,
1913 // not a non-const value. This doesn't really work
1914 // for us, as we need to be able to efficiently move
1915 // out the intermedia nlohmann::json objects. This
1916 // makes a copy of the structure, and operates on
1917 // that, but could be done more efficiently
1918 nlohmann::json ipv4Static = *ipv4StaticAddresses;
1919 handleIPv4StaticPatch(ifaceId, ipv4Static, ipv4Data, asyncResp);
1920 }
1921
1922 if (staticNameServers)
1923 {
1924 handleStaticNameServersPatch(ifaceId, *staticNameServers,
1925 asyncResp);
1926 }
1927
1928 if (ipv6DefaultGateway)
1929 {
1930 messages::propertyNotWritable(asyncResp->res,
1931 "IPv6DefaultGateway");
1932 }
1933
1934 if (ipv6StaticAddresses)
1935 {
1936 const nlohmann::json& ipv6Static = *ipv6StaticAddresses;
1937 handleIPv6StaticAddressesPatch(ifaceId, ipv6Static, ipv6Data,
1938 asyncResp);
1939 }
1940
1941 if (interfaceEnabled)
1942 {
1943 setEthernetInterfaceBoolProperty(ifaceId, "NICEnabled",
1944 *interfaceEnabled, asyncResp);
1945 }
1946
1947 if (mtuSize)
1948 {
1949 handleMTUSizePatch(ifaceId, *mtuSize, asyncResp);
1950 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001951 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001952 });
manojkiraneda2a133282019-02-19 13:09:43 +05301953
Ed Tanousbf648f72021-06-03 15:00:14 -07001954 BMCWEB_ROUTE(
1955 app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001956 .privileges(redfish::privileges::getVLanNetworkInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07001957 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001958 [&app](const crow::Request& req,
1959 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1960 const std::string& parentIfaceId,
1961 const std::string& ifaceId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001962 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001963 {
1964 return;
1965 }
1966 asyncResp->res.jsonValue["@odata.type"] =
1967 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1968 asyncResp->res.jsonValue["Name"] = "VLAN Network Interface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001969
Ed Tanous002d39b2022-05-31 08:59:27 -07001970 if (!verifyNames(parentIfaceId, ifaceId))
1971 {
1972 return;
1973 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001974
Ed Tanous002d39b2022-05-31 08:59:27 -07001975 // Get single eth interface data, and call the below callback
1976 // for JSON preparation
1977 getEthernetIfaceData(
1978 ifaceId,
1979 [asyncResp, parentIfaceId,
1980 ifaceId](const bool& success, const EthernetInterfaceData& ethData,
1981 const boost::container::flat_set<IPv4AddressData>&,
1982 const boost::container::flat_set<IPv6AddressData>&) {
1983 if (success && ethData.vlanId)
1984 {
Jiaqing Zhao22872ff2022-09-13 09:38:20 +08001985 asyncResp->res.jsonValue["Id"] = ifaceId;
1986 asyncResp->res.jsonValue["@odata.id"] =
Willy Tueddfc432022-09-26 16:46:38 +00001987 crow::utility::urlFromPieces(
1988 "redfish", "v1", "Managers", "bmc",
1989 "EthernetInterfaces", parentIfaceId, "VLANs", ifaceId);
Jiaqing Zhao22872ff2022-09-13 09:38:20 +08001990
Jiaqing Zhao23a06312022-09-13 09:38:25 +08001991 asyncResp->res.jsonValue["VLANEnable"] = ethData.nicEnabled;
Jiaqing Zhao22872ff2022-09-13 09:38:20 +08001992 asyncResp->res.jsonValue["VLANId"] = *ethData.vlanId;
Ed Tanous002d39b2022-05-31 08:59:27 -07001993 }
1994 else
1995 {
1996 // ... otherwise return error
1997 // TODO(Pawel)consider distinguish between non
1998 // existing object, and other errors
1999 messages::resourceNotFound(asyncResp->res,
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08002000 "VLanNetworkInterface", ifaceId);
Ed Tanous002d39b2022-05-31 08:59:27 -07002001 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002002 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002003 });
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01002004
Ed Tanousbf648f72021-06-03 15:00:14 -07002005 BMCWEB_ROUTE(
2006 app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/")
Abhishek Patel3d768a12021-07-31 16:44:51 -05002007 .privileges(redfish::privileges::patchVLanNetworkInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002008 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002009 [&app](const crow::Request& req,
2010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2011 const std::string& parentIfaceId,
2012 const std::string& ifaceId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002013 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002014 {
2015 return;
2016 }
2017 if (!verifyNames(parentIfaceId, ifaceId))
2018 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08002019 messages::resourceNotFound(asyncResp->res, "VLanNetworkInterface",
Ed Tanous002d39b2022-05-31 08:59:27 -07002020 ifaceId);
2021 return;
2022 }
2023
2024 std::optional<bool> vlanEnable;
2025 std::optional<uint32_t> vlanId;
2026
2027 if (!json_util::readJsonPatch(req, asyncResp->res, "VLANEnable",
2028 vlanEnable, "VLANId", vlanId))
2029 {
2030 return;
2031 }
2032
2033 if (vlanId)
2034 {
2035 messages::propertyNotWritable(asyncResp->res, "VLANId");
2036 return;
2037 }
2038
2039 // Get single eth interface data, and call the below callback
2040 // for JSON preparation
2041 getEthernetIfaceData(
2042 ifaceId,
2043 [asyncResp, parentIfaceId, ifaceId, vlanEnable](
2044 const bool& success, const EthernetInterfaceData& ethData,
2045 const boost::container::flat_set<IPv4AddressData>&,
2046 const boost::container::flat_set<IPv6AddressData>&) {
2047 if (success && ethData.vlanId)
2048 {
Jiaqing Zhao23a06312022-09-13 09:38:25 +08002049 if (vlanEnable)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002050 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002051 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002052 [asyncResp](const boost::system::error_code& ec) {
Jiaqing Zhao23a06312022-09-13 09:38:25 +08002053 if (ec)
2054 {
2055 messages::internalError(asyncResp->res);
2056 return;
2057 }
2058 },
2059 "xyz.openbmc_project.Network",
2060 "/xyz/openbmc_project/network/" + ifaceId,
2061 "org.freedesktop.DBus.Properties", "Set",
2062 "xyz.openbmc_project.Network.EthernetInterface",
2063 "NICEnabled",
2064 dbus::utility::DbusVariantType(*vlanEnable));
Ed Tanous45ca1b82022-03-25 13:07:27 -07002065 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002066 }
2067 else
2068 {
2069 // TODO(Pawel)consider distinguish between non
2070 // existing object, and other errors
2071 messages::resourceNotFound(asyncResp->res,
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08002072 "VLanNetworkInterface", ifaceId);
Ed Tanous002d39b2022-05-31 08:59:27 -07002073 return;
2074 }
Ed Tanousbf648f72021-06-03 15:00:14 -07002075 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002076 });
Ed Tanousbf648f72021-06-03 15:00:14 -07002077
2078 BMCWEB_ROUTE(
2079 app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/")
Abhishek Patel3d768a12021-07-31 16:44:51 -05002080 .privileges(redfish::privileges::deleteVLanNetworkInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002081 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002082 [&app](const crow::Request& req,
2083 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2084 const std::string& parentIfaceId,
2085 const std::string& ifaceId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002086 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002087 {
2088 return;
2089 }
2090 if (!verifyNames(parentIfaceId, ifaceId))
2091 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08002092 messages::resourceNotFound(asyncResp->res, "VLanNetworkInterface",
Ed Tanous002d39b2022-05-31 08:59:27 -07002093 ifaceId);
2094 return;
2095 }
Ed Tanousbf648f72021-06-03 15:00:14 -07002096
Ed Tanous002d39b2022-05-31 08:59:27 -07002097 // Get single eth interface data, and call the below callback
2098 // for JSON preparation
2099 getEthernetIfaceData(
2100 ifaceId,
2101 [asyncResp, parentIfaceId,
2102 ifaceId](const bool& success, const EthernetInterfaceData& ethData,
2103 const boost::container::flat_set<IPv4AddressData>&,
2104 const boost::container::flat_set<IPv6AddressData>&) {
2105 if (success && ethData.vlanId)
2106 {
2107 auto callback =
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002108 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002109 if (ec)
2110 {
2111 messages::internalError(asyncResp->res);
2112 }
2113 };
2114 crow::connections::systemBus->async_method_call(
2115 std::move(callback), "xyz.openbmc_project.Network",
2116 std::string("/xyz/openbmc_project/network/") + ifaceId,
2117 "xyz.openbmc_project.Object.Delete", "Delete");
2118 }
2119 else
2120 {
2121 // ... otherwise return error
2122 // TODO(Pawel)consider distinguish between non
2123 // existing object, and other errors
2124 messages::resourceNotFound(asyncResp->res,
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08002125 "VLanNetworkInterface", ifaceId);
Ed Tanous002d39b2022-05-31 08:59:27 -07002126 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002127 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002128 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002129
Ed Tanousbf648f72021-06-03 15:00:14 -07002130 BMCWEB_ROUTE(app,
2131 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/")
Ed Tanoused398212021-06-09 17:05:54 -07002132
2133 .privileges(redfish::privileges::getVLanNetworkInterfaceCollection)
Ed Tanous14766872022-03-15 10:44:42 -07002134 .methods(boost::beast::http::verb::get)(
2135 [&app](const crow::Request& req,
2136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2137 const std::string& rootInterfaceName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002138 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002139 {
2140 return;
2141 }
2142 // Get eth interface list, and call the below callback for JSON
2143 // preparation
2144 getEthernetIfaceList(
2145 [asyncResp, rootInterfaceName](
2146 const bool& success,
2147 const boost::container::flat_set<std::string>& ifaceList) {
2148 if (!success)
2149 {
2150 messages::internalError(asyncResp->res);
2151 return;
2152 }
2153
2154 if (ifaceList.find(rootInterfaceName) == ifaceList.end())
2155 {
2156 messages::resourceNotFound(asyncResp->res,
2157 "VLanNetworkInterfaceCollection",
2158 rootInterfaceName);
2159 return;
2160 }
2161
2162 asyncResp->res.jsonValue["@odata.type"] =
2163 "#VLanNetworkInterfaceCollection."
2164 "VLanNetworkInterfaceCollection";
2165 asyncResp->res.jsonValue["Name"] =
2166 "VLAN Network Interface Collection";
2167
2168 nlohmann::json ifaceArray = nlohmann::json::array();
2169
2170 for (const std::string& ifaceItem : ifaceList)
2171 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002172 if (ifaceItem.starts_with(rootInterfaceName + "_"))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002173 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 nlohmann::json::object_t iface;
Willy Tueddfc432022-09-26 16:46:38 +00002175 iface["@odata.id"] = crow::utility::urlFromPieces(
2176 "redfish", "v1", "Managers", "bmc",
2177 "EthernetInterfaces", rootInterfaceName, "VLANs",
2178 ifaceItem);
Ed Tanous002d39b2022-05-31 08:59:27 -07002179 ifaceArray.push_back(std::move(iface));
Ed Tanous1abe55e2018-09-05 08:30:59 -07002180 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002181 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002182
Ed Tanous002d39b2022-05-31 08:59:27 -07002183 asyncResp->res.jsonValue["Members@odata.count"] = ifaceArray.size();
2184 asyncResp->res.jsonValue["Members"] = std::move(ifaceArray);
2185 asyncResp->res.jsonValue["@odata.id"] =
Willy Tueddfc432022-09-26 16:46:38 +00002186 crow::utility::urlFromPieces("redfish", "v1", "Managers", "bmc",
2187 "EthernetInterfaces",
2188 rootInterfaceName, "VLANs");
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 });
2190 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002191
Ed Tanousbf648f72021-06-03 15:00:14 -07002192 BMCWEB_ROUTE(app,
2193 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/")
Abhishek Patel3d768a12021-07-31 16:44:51 -05002194 .privileges(redfish::privileges::postVLanNetworkInterfaceCollection)
Ed Tanousbf648f72021-06-03 15:00:14 -07002195 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002196 [&app](const crow::Request& req,
2197 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2198 const std::string& rootInterfaceName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002199 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002200 {
2201 return;
2202 }
2203 bool vlanEnable = false;
2204 uint32_t vlanId = 0;
2205 if (!json_util::readJsonPatch(req, asyncResp->res, "VLANId", vlanId,
2206 "VLANEnable", vlanEnable))
2207 {
2208 return;
2209 }
2210 // Need both vlanId and vlanEnable to service this request
2211 if (vlanId == 0U)
2212 {
2213 messages::propertyMissing(asyncResp->res, "VLANId");
2214 }
2215 if (!vlanEnable)
2216 {
2217 messages::propertyMissing(asyncResp->res, "VLANEnable");
2218 }
2219 if (static_cast<bool>(vlanId) ^ vlanEnable)
2220 {
2221 return;
2222 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002223
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002224 auto callback = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002225 if (ec)
2226 {
2227 // TODO(ed) make more consistent error messages
2228 // based on phosphor-network responses
2229 messages::internalError(asyncResp->res);
2230 return;
2231 }
2232 messages::created(asyncResp->res);
2233 };
2234 crow::connections::systemBus->async_method_call(
2235 std::move(callback), "xyz.openbmc_project.Network",
2236 "/xyz/openbmc_project/network",
2237 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
2238 rootInterfaceName, vlanId);
2239 });
Ed Tanousbf648f72021-06-03 15:00:14 -07002240}
2241
Ed Tanous1abe55e2018-09-05 08:30:59 -07002242} // namespace redfish