blob: 26d7ddcd0b67847dfadf1c7d6986c817c1b0ae9a [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 Tanous1abe55e2018-09-05 08:30:59 -070018#include <boost/container/flat_map.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070019#include <boost/container/flat_set.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020020#include <dbus_singleton.hpp>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020021#include <error_messages.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020022#include <node.hpp>
Ed Tanousa24526d2018-12-10 15:17:59 -080023#include <optional>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020024#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080025#include <variant>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010029
30/**
31 * DBus types primitives for several generic DBus interfaces
32 * TODO(Pawel) consider move this to separate file into boost::dbus
33 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using PropertiesMapType = boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080035 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36 int32_t, uint32_t, int64_t, uint64_t, double>>;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010037
Ed Tanous4a0cb852018-10-15 07:55:04 -070038using GetManagedObjects = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039 sdbusplus::message::object_path,
Ed Tanous4a0cb852018-10-15 07:55:04 -070040 std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070041 std::string,
42 boost::container::flat_map<
Ed Tanous029573d2019-02-01 10:57:49 -080043 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
45 int32_t, uint32_t, int64_t, uint64_t, double,
46 std::vector<std::string>>>>>>>;
Ed Tanous4a0cb852018-10-15 07:55:04 -070047
48enum class LinkType
49{
50 Local,
51 Global
52};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010053
54/**
55 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010056 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070057struct IPv4AddressData
58{
59 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070060 std::string address;
61 std::string domain;
62 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 std::string netmask;
64 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070065 LinkType linktype;
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 bool operator<(const IPv4AddressData &obj) const
68 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070069 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
74 * Structure for keeping basic single Ethernet Interface information
75 * available from DBus
76 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070077struct EthernetInterfaceData
78{
Ed Tanous4a0cb852018-10-15 07:55:04 -070079 uint32_t speed;
80 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053081 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070082 std::string hostname;
83 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -050084 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -070085 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -050086 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -080087 std::vector<std::string> nameservers;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010088};
89
Ed Tanous4a0cb852018-10-15 07:55:04 -070090// Helper function that changes bits netmask notation (i.e. /24)
91// into full dot notation
92inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -070093{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t value = 0xffffffff << (32 - bits);
95 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
96 std::to_string((value >> 16) & 0xff) + "." +
97 std::to_string((value >> 8) & 0xff) + "." +
98 std::to_string(value & 0xff);
99 return netmask;
100}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100101
Ed Tanous4a0cb852018-10-15 07:55:04 -0700102inline std::string
103 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
104 bool isIPv4)
105{
106 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700108 return "Static";
109 }
110 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
111 {
112 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700114 return "IPv4LinkLocal";
115 }
116 else
117 {
118 return "LinkLocal";
119 }
120 }
121 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
122 {
123 if (isIPv4)
124 {
125 return "DHCP";
126 }
127 else
128 {
129 return "DHCPv6";
130 }
131 }
132 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
133 {
134 return "SLAAC";
135 }
136 return "";
137}
138
139inline std::string
140 translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
141{
142 if (inputOrigin == "Static")
143 {
144 return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
145 }
146 if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
147 {
148 return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
149 }
150 if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
151 {
152 return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
153 }
154 if (inputOrigin == "SLAAC")
155 {
156 return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
157 }
158 return "";
159}
160
Ed Tanous4c9afe42019-05-03 16:59:57 -0700161inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700162 const GetManagedObjects &dbus_data,
163 EthernetInterfaceData &ethData)
164{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700165 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700166 for (const auto &objpath : dbus_data)
167 {
Ed Tanous029573d2019-02-01 10:57:49 -0800168 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700169 {
Ed Tanous029573d2019-02-01 10:57:49 -0800170 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700172 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700173 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700175 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700177 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700179 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800180 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700181 if (mac != nullptr)
182 {
183 ethData.mac_address = *mac;
184 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700186 }
187 }
188 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
189 {
190 for (const auto &propertyPair : ifacePair.second)
191 {
192 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800194 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800195 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700196 if (id != nullptr)
197 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500198 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700199 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700201 }
202 }
203 else if (ifacePair.first ==
204 "xyz.openbmc_project.Network.EthernetInterface")
205 {
206 for (const auto &propertyPair : ifacePair.second)
207 {
208 if (propertyPair.first == "AutoNeg")
209 {
210 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800211 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700212 if (auto_neg != nullptr)
213 {
214 ethData.auto_neg = *auto_neg;
215 }
216 }
217 else if (propertyPair.first == "Speed")
218 {
219 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800220 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700221 if (speed != nullptr)
222 {
223 ethData.speed = *speed;
224 }
225 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500226 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700227 {
Ed Tanous029573d2019-02-01 10:57:49 -0800228 const std::vector<std::string> *nameservers =
229 sdbusplus::message::variant_ns::get_if<
230 std::vector<std::string>>(
231 &propertyPair.second);
232 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700233 {
Ed Tanous029573d2019-02-01 10:57:49 -0800234 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700235 }
236 }
manojkiraneda2a133282019-02-19 13:09:43 +0530237 else if (propertyPair.first == "DHCPEnabled")
238 {
239 const bool *DHCPEnabled =
240 std::get_if<bool>(&propertyPair.second);
241 if (DHCPEnabled != nullptr)
242 {
243 ethData.DHCPEnabled = *DHCPEnabled;
244 }
245 }
Ed Tanous029573d2019-02-01 10:57:49 -0800246 }
247 }
248 }
249 // System configuration shows up in the global namespace, so no need
250 // to check eth number
251 if (ifacePair.first ==
252 "xyz.openbmc_project.Network.SystemConfiguration")
253 {
254 for (const auto &propertyPair : ifacePair.second)
255 {
256 if (propertyPair.first == "HostName")
257 {
258 const std::string *hostname =
259 sdbusplus::message::variant_ns::get_if<std::string>(
260 &propertyPair.second);
261 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700262 {
Ed Tanous029573d2019-02-01 10:57:49 -0800263 ethData.hostname = *hostname;
264 }
265 }
266 else if (propertyPair.first == "DefaultGateway")
267 {
268 const std::string *defaultGateway =
269 sdbusplus::message::variant_ns::get_if<std::string>(
270 &propertyPair.second);
271 if (defaultGateway != nullptr)
272 {
273 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700274 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500276 else if (propertyPair.first == "DefaultGateway6")
277 {
278 const std::string *defaultGateway6 =
279 sdbusplus::message::variant_ns::get_if<std::string>(
280 &propertyPair.second);
281 if (defaultGateway6 != nullptr)
282 {
283 ethData.ipv6_default_gateway = *defaultGateway6;
284 }
285 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 }
287 }
288 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700290 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700291}
292
293// Helper function that extracts data for single ethernet ipv4 address
294inline void
295 extractIPData(const std::string &ethiface_id,
296 const GetManagedObjects &dbus_data,
297 boost::container::flat_set<IPv4AddressData> &ipv4_config)
298{
299 const std::string ipv4PathStart =
300 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
301
302 // Since there might be several IPv4 configurations aligned with
303 // single ethernet interface, loop over all of them
304 for (const auto &objpath : dbus_data)
305 {
306 // Check if proper pattern for object path appears
307 if (boost::starts_with(objpath.first.str, ipv4PathStart))
308 {
309 for (auto &interface : objpath.second)
310 {
311 if (interface.first == "xyz.openbmc_project.Network.IP")
312 {
313 // Instance IPv4AddressData structure, and set as
314 // appropriate
315 std::pair<
316 boost::container::flat_set<IPv4AddressData>::iterator,
317 bool>
318 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000319 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700320 IPv4AddressData &ipv4_address = *it.first;
321 for (auto &property : interface.second)
322 {
323 if (property.first == "Address")
324 {
325 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800326 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700327 if (address != nullptr)
328 {
329 ipv4_address.address = *address;
330 }
331 }
332 else if (property.first == "Gateway")
333 {
334 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800335 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700336 if (gateway != nullptr)
337 {
338 ipv4_address.gateway = *gateway;
339 }
340 }
341 else if (property.first == "Origin")
342 {
343 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800344 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700345 if (origin != nullptr)
346 {
347 ipv4_address.origin =
348 translateAddressOriginDbusToRedfish(*origin,
349 true);
350 }
351 }
352 else if (property.first == "PrefixLength")
353 {
354 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800355 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700356 if (mask != nullptr)
357 {
358 // convert it to the string
359 ipv4_address.netmask = getNetmask(*mask);
360 }
361 }
362 else
363 {
364 BMCWEB_LOG_ERROR
365 << "Got extra property: " << property.first
366 << " on the " << objpath.first.str << " object";
367 }
368 }
369 // Check if given address is local, or global
370 ipv4_address.linktype =
371 boost::starts_with(ipv4_address.address, "169.254.")
372 ? LinkType::Global
373 : LinkType::Local;
374 }
375 }
376 }
377 }
378}
379
380/**
381 * @brief Sets given Id on the given VLAN interface through D-Bus
382 *
383 * @param[in] ifaceId Id of VLAN interface that should be modified
384 * @param[in] inputVlanId New ID of the VLAN
385 * @param[in] callback Function that will be called after the operation
386 *
387 * @return None.
388 */
389template <typename CallbackFunc>
390void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
391 CallbackFunc &&callback)
392{
393 crow::connections::systemBus->async_method_call(
394 callback, "xyz.openbmc_project.Network",
395 std::string("/xyz/openbmc_project/network/") + ifaceId,
396 "org.freedesktop.DBus.Properties", "Set",
397 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800398 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700399}
400
401/**
402 * @brief Helper function that verifies IP address to check if it is in
403 * proper format. If bits pointer is provided, also calculates active
404 * bit count for Subnet Mask.
405 *
406 * @param[in] ip IP that will be verified
407 * @param[out] bits Calculated mask in bits notation
408 *
409 * @return true in case of success, false otherwise
410 */
411inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
412 uint8_t *bits = nullptr)
413{
414 std::vector<std::string> bytesInMask;
415
416 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417
418 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700419 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700421 return false;
422 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700423
Ed Tanous4a0cb852018-10-15 07:55:04 -0700424 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700426 *bits = 0;
427 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700428
Ed Tanous4a0cb852018-10-15 07:55:04 -0700429 char *endPtr;
430 long previousValue = 255;
431 bool firstZeroInByteHit;
432 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700434 if (byte.empty())
435 {
436 return false;
437 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438
Ed Tanous4a0cb852018-10-15 07:55:04 -0700439 // Use strtol instead of stroi to avoid exceptions
440 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441
Ed Tanous4a0cb852018-10-15 07:55:04 -0700442 // endPtr should point to the end of the string, otherwise given string
443 // is not 100% number
444 if (*endPtr != '\0')
445 {
446 return false;
447 }
448
449 // Value should be contained in byte
450 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 {
452 return false;
453 }
454
455 if (bits != nullptr)
456 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700457 // Mask has to be continuous between bytes
458 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 {
460 return false;
461 }
462
Ed Tanous4a0cb852018-10-15 07:55:04 -0700463 // Mask has to be continuous inside bytes
464 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465
Ed Tanous4a0cb852018-10-15 07:55:04 -0700466 // Count bits
467 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700469 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700471 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700473 // Continuity not preserved
474 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 }
476 else
477 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700478 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 }
480 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 else
482 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700483 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700485 }
486 }
487
488 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 }
490
Ed Tanous4a0cb852018-10-15 07:55:04 -0700491 return true;
492}
493
494/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000495 * @brief Changes IPv4 address type property (Address, Gateway)
496 *
497 * @param[in] ifaceId Id of interface whose IP should be modified
498 * @param[in] ipIdx Index of IP in input array that should be modified
499 * @param[in] ipHash DBus Hash id of modified IP
500 * @param[in] name Name of field in JSON representation
501 * @param[in] newValue New value that should be written
502 * @param[io] asyncResp Response object that will be returned to client
503 *
504 * @return true if give IP is valid and has been sent do D-Bus, false
505 * otherwise
506 */
507inline void changeIPv4AddressProperty(
508 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
509 const std::string &name, const std::string &newValue,
510 const std::shared_ptr<AsyncResp> asyncResp)
511{
512 auto callback = [asyncResp, ipIdx, name{std::string(name)},
513 newValue{std::move(newValue)}](
514 const boost::system::error_code ec) {
515 if (ec)
516 {
517 messages::internalError(asyncResp->res);
518 }
519 else
520 {
521 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
522 }
523 };
524
525 crow::connections::systemBus->async_method_call(
526 std::move(callback), "xyz.openbmc_project.Network",
527 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
528 "org.freedesktop.DBus.Properties", "Set",
529 "xyz.openbmc_project.Network.IP", name,
530 std::variant<std::string>(newValue));
531}
532
533/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700534 * @brief Changes IPv4 address origin property
535 *
536 * @param[in] ifaceId Id of interface whose IP should be modified
537 * @param[in] ipIdx Index of IP in input array that should be
538 * modified
539 * @param[in] ipHash DBus Hash id of modified IP
540 * @param[in] newValue New value in Redfish format
541 * @param[in] newValueDbus New value in D-Bus format
542 * @param[io] asyncResp Response object that will be returned to client
543 *
544 * @return true if give IP is valid and has been sent do D-Bus, false
545 * otherwise
546 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000547inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548 const std::string &ipHash,
549 const std::string &newValue,
550 const std::string &newValueDbus,
551 const std::shared_ptr<AsyncResp> asyncResp)
552{
553 auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
554 const boost::system::error_code ec) {
555 if (ec)
556 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800557 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700558 }
559 else
560 {
561 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
562 newValue;
563 }
564 };
565
566 crow::connections::systemBus->async_method_call(
567 std::move(callback), "xyz.openbmc_project.Network",
568 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
569 "org.freedesktop.DBus.Properties", "Set",
570 "xyz.openbmc_project.Network.IP", "Origin",
Ed Tanousabf2add2019-01-22 16:40:12 -0800571 std::variant<std::string>(newValueDbus));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700572}
573
574/**
575 * @brief Modifies SubnetMask for given IP
576 *
577 * @param[in] ifaceId Id of interface whose IP should be modified
578 * @param[in] ipIdx Index of IP in input array that should be
579 * modified
580 * @param[in] ipHash DBus Hash id of modified IP
581 * @param[in] newValueStr Mask in dot notation as string
582 * @param[in] newValue Mask as PrefixLength in bitcount
583 * @param[io] asyncResp Response object that will be returned to client
584 *
585 * @return None
586 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000587inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700588 const std::string &ipHash,
589 const std::string &newValueStr,
590 uint8_t &newValue,
591 std::shared_ptr<AsyncResp> asyncResp)
592{
593 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
594 const boost::system::error_code ec) {
595 if (ec)
596 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800597 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700598 }
599 else
600 {
601 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
602 newValueStr;
603 }
604 };
605
606 crow::connections::systemBus->async_method_call(
607 std::move(callback), "xyz.openbmc_project.Network",
608 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
609 "org.freedesktop.DBus.Properties", "Set",
610 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800611 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700612}
613
614/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700615 * @brief Deletes given IPv4
616 *
617 * @param[in] ifaceId Id of interface whose IP should be deleted
618 * @param[in] ipIdx Index of IP in input array that should be deleted
619 * @param[in] ipHash DBus Hash id of IP that should be deleted
620 * @param[io] asyncResp Response object that will be returned to client
621 *
622 * @return None
623 */
624inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
625 unsigned int ipIdx,
626 const std::shared_ptr<AsyncResp> asyncResp)
627{
628 crow::connections::systemBus->async_method_call(
629 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 if (ec)
631 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800632 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100633 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700634 else
635 {
636 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
637 }
638 },
639 "xyz.openbmc_project.Network",
640 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
641 "xyz.openbmc_project.Object.Delete", "Delete");
642}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643
Ed Tanous4a0cb852018-10-15 07:55:04 -0700644/**
645 * @brief Creates IPv4 with given data
646 *
647 * @param[in] ifaceId Id of interface whose IP should be deleted
648 * @param[in] ipIdx Index of IP in input array that should be deleted
649 * @param[in] ipHash DBus Hash id of IP that should be deleted
650 * @param[io] asyncResp Response object that will be returned to client
651 *
652 * @return None
653 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000654inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
655 uint8_t subnetMask, const std::string &gateway,
656 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700657 std::shared_ptr<AsyncResp> asyncResp)
658{
Ed Tanous43b761d2019-02-13 20:10:56 -0800659 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700660 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800662 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 };
665
Ed Tanous4a0cb852018-10-15 07:55:04 -0700666 crow::connections::systemBus->async_method_call(
667 std::move(createIpHandler), "xyz.openbmc_project.Network",
668 "/xyz/openbmc_project/network/" + ifaceId,
669 "xyz.openbmc_project.Network.IP.Create", "IP",
670 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
671 gateway);
672}
manojkiraneda2a133282019-02-19 13:09:43 +0530673using GetAllPropertiesType =
674 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
675
676inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
677{
678 auto getConfig = [asyncResp](const boost::system::error_code error_code,
679 const GetAllPropertiesType &dbus_data) {
680 if (error_code)
681 {
682 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
683 messages::internalError(asyncResp->res);
684 return;
685 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500686 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530687 for (const auto &property : dbus_data)
688 {
689 auto value =
690 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
691
692 if (value == nullptr)
693 {
694 continue;
695 }
696 if (property.first == "DNSEnabled")
697 {
698 DHCPConfigTypeJson["UseDNSServers"] = *value;
699 }
700 else if (property.first == "HostNameEnabled")
701 {
702 DHCPConfigTypeJson["UseDomainName"] = *value;
703 }
704 else if (property.first == "NTPEnabled")
705 {
706 DHCPConfigTypeJson["UseNTPServers"] = *value;
707 }
708 }
709 };
710 crow::connections::systemBus->async_method_call(
711 std::move(getConfig), "xyz.openbmc_project.Network",
712 "/xyz/openbmc_project/network/config/dhcp",
713 "org.freedesktop.DBus.Properties", "GetAll",
714 "xyz.openbmc_project.Network.DHCPConfiguration");
715}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716
Ed Tanous4a0cb852018-10-15 07:55:04 -0700717/**
718 * Function that retrieves all properties for given Ethernet Interface
719 * Object
720 * from EntityManager Network Manager
721 * @param ethiface_id a eth interface id to query on DBus
722 * @param callback a function that shall be called to convert Dbus output
723 * into JSON
724 */
725template <typename CallbackFunc>
726void getEthernetIfaceData(const std::string &ethiface_id,
727 CallbackFunc &&callback)
728{
729 crow::connections::systemBus->async_method_call(
730 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
731 const boost::system::error_code error_code,
732 const GetManagedObjects &resp) {
733 EthernetInterfaceData ethData{};
734 boost::container::flat_set<IPv4AddressData> ipv4Data;
735
736 if (error_code)
737 {
738 callback(false, ethData, ipv4Data);
739 return;
740 }
741
Ed Tanous4c9afe42019-05-03 16:59:57 -0700742 bool found =
743 extractEthernetInterfaceData(ethiface_id, resp, ethData);
744 if (!found)
745 {
746 callback(false, ethData, ipv4Data);
747 return;
748 }
749
Ed Tanous4a0cb852018-10-15 07:55:04 -0700750 extractIPData(ethiface_id, resp, ipv4Data);
751
752 // Fix global GW
753 for (IPv4AddressData &ipv4 : ipv4Data)
754 {
755 if ((ipv4.linktype == LinkType::Global) &&
756 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700758 ipv4.gateway = ethData.default_gateway;
759 }
760 }
761
762 // Finally make a callback with usefull data
763 callback(true, ethData, ipv4Data);
764 },
765 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
766 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
767};
768
769/**
770 * Function that retrieves all Ethernet Interfaces available through Network
771 * Manager
772 * @param callback a function that shall be called to convert Dbus output
773 * into JSON.
774 */
775template <typename CallbackFunc>
776void getEthernetIfaceList(CallbackFunc &&callback)
777{
778 crow::connections::systemBus->async_method_call(
779 [callback{std::move(callback)}](
780 const boost::system::error_code error_code,
781 GetManagedObjects &resp) {
782 // Callback requires vector<string> to retrieve all available
783 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700784 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700785 iface_list.reserve(resp.size());
786 if (error_code)
787 {
788 callback(false, iface_list);
789 return;
790 }
791
792 // Iterate over all retrieved ObjectPaths.
793 for (const auto &objpath : resp)
794 {
795 // And all interfaces available for certain ObjectPath.
796 for (const auto &interface : objpath.second)
797 {
798 // If interface is
799 // xyz.openbmc_project.Network.EthernetInterface, this is
800 // what we're looking for.
801 if (interface.first ==
802 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700804 // Cut out everyting until last "/", ...
805 const std::string &iface_id = objpath.first.str;
806 std::size_t last_pos = iface_id.rfind("/");
807 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700809 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700810 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 }
812 }
813 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700814 }
815 // Finally make a callback with useful data
816 callback(true, iface_list);
817 },
818 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
819 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100820};
821
822/**
823 * EthernetCollection derived class for delivering Ethernet Collection Schema
824 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825class EthernetCollection : public Node
826{
827 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700828 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700830 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 entityPrivileges = {
833 {boost::beast::http::verb::get, {{"Login"}}},
834 {boost::beast::http::verb::head, {{"Login"}}},
835 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
836 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
837 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
838 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
839 }
840
841 private:
842 /**
843 * Functions triggers appropriate requests on DBus
844 */
845 void doGet(crow::Response &res, const crow::Request &req,
846 const std::vector<std::string> &params) override
847 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800848 res.jsonValue["@odata.type"] =
849 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
850 res.jsonValue["@odata.context"] =
851 "/redfish/v1/"
852 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
853 res.jsonValue["@odata.id"] =
854 "/redfish/v1/Managers/bmc/EthernetInterfaces";
855 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
856 res.jsonValue["Description"] =
857 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700858 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700859 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700861 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700862 [asyncResp](
863 const bool &success,
864 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700865 if (!success)
866 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700867 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700868 return;
869 }
870
Ed Tanous4c9afe42019-05-03 16:59:57 -0700871 nlohmann::json &iface_array =
872 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700873 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500874 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700875 for (const std::string &iface_item : iface_list)
876 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500877 std::size_t found = iface_item.find(tag);
878 if (found == std::string::npos)
879 {
880 iface_array.push_back(
881 {{"@odata.id",
882 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
883 iface_item}});
884 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700885 }
886
Ed Tanous4c9afe42019-05-03 16:59:57 -0700887 asyncResp->res.jsonValue["Members@odata.count"] =
888 iface_array.size();
889 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700890 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700891 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700892 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100893};
894
895/**
896 * EthernetInterface derived class for delivering Ethernet Schema
897 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898class EthernetInterface : public Node
899{
900 public:
901 /*
902 * Default Constructor
903 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700904 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700906 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 std::string())
908 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 entityPrivileges = {
910 {boost::beast::http::verb::get, {{"Login"}}},
911 {boost::beast::http::verb::head, {{"Login"}}},
912 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
913 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
914 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
915 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200916 }
917
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800919 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700920 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800922 asyncResp->res.jsonValue["HostName"] = hostname;
923 crow::connections::systemBus->async_method_call(
924 [asyncResp](const boost::system::error_code ec) {
925 if (ec)
926 {
927 messages::internalError(asyncResp->res);
928 }
929 },
930 "xyz.openbmc_project.Network",
931 "/xyz/openbmc_project/network/config",
932 "org.freedesktop.DBus.Properties", "Set",
933 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -0800934 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 }
936
Ratan Guptad5776652019-03-03 08:47:22 +0530937 void handleMACAddressPatch(const std::string &ifaceId,
938 const std::string &macAddress,
939 const std::shared_ptr<AsyncResp> &asyncResp)
940 {
941 crow::connections::systemBus->async_method_call(
942 [asyncResp, macAddress](const boost::system::error_code ec) {
943 if (ec)
944 {
945 messages::internalError(asyncResp->res);
946 return;
947 }
948 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
949 },
950 "xyz.openbmc_project.Network",
951 "/xyz/openbmc_project/network/" + ifaceId,
952 "org.freedesktop.DBus.Properties", "Set",
953 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
954 std::variant<std::string>(macAddress));
955 }
Jennifer Leeda131a92019-04-24 15:13:55 -0700956 void setDHCPEnabled(const std::string &ifaceId,
957 const std::string &propertyName, const bool &value,
958 const std::shared_ptr<AsyncResp> asyncResp)
959 {
960 crow::connections::systemBus->async_method_call(
961 [asyncResp](const boost::system::error_code ec) {
962 if (ec)
963 {
964 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
965 messages::internalError(asyncResp->res);
966 return;
967 }
968 },
969 "xyz.openbmc_project.Network",
970 "/xyz/openbmc_project/network/" + ifaceId,
971 "org.freedesktop.DBus.Properties", "Set",
972 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
973 std::variant<bool>{value});
974 }
975 void setDHCPv4Config(const std::string &propertyName, const bool &value,
976 const std::shared_ptr<AsyncResp> asyncResp)
977 {
978 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
979 crow::connections::systemBus->async_method_call(
980 [asyncResp](const boost::system::error_code ec) {
981 if (ec)
982 {
983 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
984 messages::internalError(asyncResp->res);
985 return;
986 }
987 },
988 "xyz.openbmc_project.Network",
989 "/xyz/openbmc_project/network/config/dhcp",
990 "org.freedesktop.DBus.Properties", "Set",
991 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
992 std::variant<bool>{value});
993 }
Ratan Guptad5776652019-03-03 08:47:22 +0530994
Jennifer Leeda131a92019-04-24 15:13:55 -0700995 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
996 const std::shared_ptr<AsyncResp> asyncResp)
997 {
998 std::optional<bool> dhcpEnabled;
999 std::optional<bool> useDNSServers;
1000 std::optional<bool> useDomainName;
1001 std::optional<bool> useNTPServers;
1002
1003 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1004 dhcpEnabled, "UseDNSServers", useDNSServers,
1005 "UseDomainName", useDomainName,
1006 "UseNTPServers", useNTPServers))
1007 {
1008 return;
1009 }
1010
1011 if (dhcpEnabled)
1012 {
1013 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1014 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1015 }
1016
1017 if (useDNSServers)
1018 {
1019 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1020 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1021 }
1022
1023 if (useDomainName)
1024 {
1025 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1026 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1027 }
1028
1029 if (useNTPServers)
1030 {
1031 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1032 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1033 }
1034 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001035 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301036 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001037 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1038 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001039 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301040 if (!input.is_array())
1041 {
1042 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1043 "IPv4Addresses");
1044 return;
1045 }
1046
Ed Tanous4a0cb852018-10-15 07:55:04 -07001047 int entryIdx = 0;
1048 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1049 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001050 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001051 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001052 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001053 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001054
Ratan Guptaf476acb2019-03-02 16:46:57 +05301055 if (thisJson.is_null())
1056 {
1057 if (thisData != ipv4Data.end())
1058 {
1059 deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
1060 thisData++;
1061 }
1062 else
1063 {
1064 messages::propertyValueFormatError(
1065 asyncResp->res, input.dump(), pathString);
1066 return;
1067 // TODO(ratagupt) Not sure about the property where value is
1068 // list and if unable to update one of the
1069 // list value then should we proceed further or
1070 // break there, would ask in the redfish forum
1071 // till then we stop processing the next list item.
1072 }
1073 entryIdx++;
1074 continue; // not an error as per the redfish spec.
1075 }
1076
Ratan Gupta9474b372019-03-01 15:13:37 +05301077 if (thisJson.empty())
1078 {
1079 if (thisData != ipv4Data.end())
1080 {
1081 thisData++;
1082 }
1083 else
1084 {
1085 messages::propertyMissing(asyncResp->res,
1086 pathString + "/Address");
1087 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301088 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301089 // list and if unable to update one of the
1090 // list value then should we proceed further or
1091 // break there, would ask in the redfish forum
1092 // till then we stop processing the next list item.
1093 }
1094 entryIdx++;
1095 continue; // not an error as per the redfish spec.
1096 }
1097
Ed Tanous537174c2018-12-10 15:09:31 -08001098 std::optional<std::string> address;
1099 std::optional<std::string> addressOrigin;
1100 std::optional<std::string> subnetMask;
1101 std::optional<std::string> gateway;
1102
1103 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1104 address, "AddressOrigin", addressOrigin,
1105 "SubnetMask", subnetMask, "Gateway",
1106 gateway))
1107 {
1108 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001109 }
1110
Ed Tanous537174c2018-12-10 15:09:31 -08001111 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001112 {
Ed Tanous537174c2018-12-10 15:09:31 -08001113 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001114 {
Ed Tanous537174c2018-12-10 15:09:31 -08001115 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001116 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001117 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001118 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001119 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001120
Ed Tanous537174c2018-12-10 15:09:31 -08001121 uint8_t prefixLength = 0;
1122 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001123 {
Ed Tanous537174c2018-12-10 15:09:31 -08001124 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001125 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001126 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001127 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001128 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001129 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001130 }
1131 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001132 std::string addressOriginInDBusFormat;
Ed Tanous537174c2018-12-10 15:09:31 -08001133 if (addressOrigin)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001134 {
Ed Tanous537174c2018-12-10 15:09:31 -08001135 // Get Address origin in proper format
1136 addressOriginInDBusFormat =
1137 translateAddressOriginRedfishToDbus(*addressOrigin);
1138 if (addressOriginInDBusFormat.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001139 {
Ed Tanous537174c2018-12-10 15:09:31 -08001140 messages::propertyValueNotInList(
1141 asyncResp->res, *addressOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001142 pathString + "/AddressOrigin");
Ed Tanous537174c2018-12-10 15:09:31 -08001143 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001144 }
1145 }
1146
Ed Tanous537174c2018-12-10 15:09:31 -08001147 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001148 {
Ed Tanous537174c2018-12-10 15:09:31 -08001149 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001150 {
Ed Tanous537174c2018-12-10 15:09:31 -08001151 messages::propertyValueFormatError(asyncResp->res, *gateway,
1152 pathString + "/Gateway");
1153 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001154 }
1155 }
1156
Ratan Guptaf476acb2019-03-02 16:46:57 +05301157 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001158 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001159 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301160 // Apply changes
1161 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001162 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301163 auto callback = [asyncResp, entryIdx,
1164 address{std::string(*address)}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001165 const boost::system::error_code ec) {
1166 if (ec)
1167 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001168 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001169 return;
1170 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301171 asyncResp->res
1172 .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1173 std::move(address);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001174 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301175
Ed Tanous4a0cb852018-10-15 07:55:04 -07001176 crow::connections::systemBus->async_method_call(
1177 std::move(callback), "xyz.openbmc_project.Network",
1178 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1179 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301180 "org.freedesktop.DBus.Properties", "Set",
1181 "xyz.openbmc_project.Network.IP", "Address",
1182 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001183 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301184
1185 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001186 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301187 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1188 thisData->id, *subnetMask,
1189 prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301191
1192 if (addressOrigin)
1193 {
1194 changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1195 *addressOrigin, addressOriginInDBusFormat,
1196 asyncResp);
1197 }
1198
1199 if (gateway)
1200 {
1201 auto callback = [asyncResp, entryIdx,
1202 gateway{std::string(*gateway)}](
1203 const boost::system::error_code ec) {
1204 if (ec)
1205 {
1206 messages::internalError(asyncResp->res);
1207 return;
1208 }
1209 asyncResp->res
1210 .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1211 std::move(gateway);
1212 };
1213
1214 crow::connections::systemBus->async_method_call(
1215 std::move(callback), "xyz.openbmc_project.Network",
1216 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1217 thisData->id,
1218 "org.freedesktop.DBus.Properties", "Set",
1219 "xyz.openbmc_project.Network.IP", "Gateway",
1220 std::variant<std::string>(*gateway));
1221 }
1222
Ed Tanous4a0cb852018-10-15 07:55:04 -07001223 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001224 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001225 else
1226 {
1227 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001228 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001229 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001230 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001231 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001232 continue;
1233 }
1234
Ed Tanous537174c2018-12-10 15:09:31 -08001235 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001236 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001237 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001238 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001239 continue;
1240 }
1241
Ed Tanous537174c2018-12-10 15:09:31 -08001242 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001243 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001244 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001245 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001246 continue;
1247 }
1248
Ed Tanousb01bf292019-03-25 19:25:26 +00001249 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1250 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301251
1252 nlohmann::json &ipv4AddressJson =
1253 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1254 ipv4AddressJson["Address"] = *address;
1255 ipv4AddressJson["SubnetMask"] = *subnetMask;
1256 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001257 }
1258 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001259 }
1260 }
1261
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001262 void handleStaticNameServersPatch(
1263 const std::string &ifaceId,
1264 const std::vector<std::string> &updatedStaticNameServers,
1265 const std::shared_ptr<AsyncResp> &asyncResp)
1266 {
1267 crow::connections::systemBus->async_method_call(
1268 [asyncResp,
1269 updatedStaticNameServers](const boost::system::error_code ec) {
1270 if (ec)
1271 {
1272 messages::internalError(asyncResp->res);
1273 return;
1274 }
1275 asyncResp->res.jsonValue["NameServers"] =
1276 updatedStaticNameServers;
1277 asyncResp->res.jsonValue["StaticNameServers"] =
1278 updatedStaticNameServers;
1279 },
1280 "xyz.openbmc_project.Network",
1281 "/xyz/openbmc_project/network/" + ifaceId,
1282 "org.freedesktop.DBus.Properties", "Set",
1283 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1284 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1285 }
1286
Ed Tanous0f74e642018-11-12 15:17:05 -08001287 void parseInterfaceData(
1288 nlohmann::json &json_response, const std::string &iface_id,
1289 const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001290 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001291 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001292 json_response["Id"] = iface_id;
1293 json_response["@odata.id"] =
1294 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001295 json_response["InterfaceEnabled"] = true;
1296 if (ethData.speed == 0)
1297 {
1298 json_response["LinkStatus"] = "NoLink";
1299 json_response["Status"] = {
1300 {"Health", "OK"},
1301 {"State", "Disabled"},
1302 };
1303 }
1304 else
1305 {
1306 json_response["LinkStatus"] = "LinkUp";
1307 json_response["Status"] = {
1308 {"Health", "OK"},
1309 {"State", "Enabled"},
1310 };
1311 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001312 json_response["SpeedMbps"] = ethData.speed;
1313 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001314 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301315
Ed Tanous4a0cb852018-10-15 07:55:04 -07001316 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001317 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001318 json_response["HostName"] = ethData.hostname;
1319 }
1320
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001321 json_response["VLANs"] = {
1322 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1323 iface_id + "/VLANs"}};
1324
Ed Tanous029573d2019-02-01 10:57:49 -08001325 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001326 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001327
Ed Tanous4a0cb852018-10-15 07:55:04 -07001328 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001329 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001330 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1331 ipv4_array = nlohmann::json::array();
1332 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001334
1335 std::string gatewayStr = ipv4_config.gateway;
1336 if (gatewayStr.empty())
1337 {
1338 gatewayStr = "0.0.0.0";
1339 }
1340
Ed Tanous029573d2019-02-01 10:57:49 -08001341 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1342 {"SubnetMask", ipv4_config.netmask},
1343 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001344 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001346 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001347 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348 }
1349
1350 /**
1351 * Functions triggers appropriate requests on DBus
1352 */
1353 void doGet(crow::Response &res, const crow::Request &req,
1354 const std::vector<std::string> &params) override
1355 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001356 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001357 if (params.size() != 1)
1358 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001359 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001360 return;
1361 }
1362
Ed Tanous4a0cb852018-10-15 07:55:04 -07001363 getEthernetIfaceData(
1364 params[0],
1365 [this, asyncResp, iface_id{std::string(params[0])}](
1366 const bool &success, const EthernetInterfaceData &ethData,
1367 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1368 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001369 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001370 // TODO(Pawel)consider distinguish between non existing
1371 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001372 messages::resourceNotFound(asyncResp->res,
1373 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001374 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001375 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001376
1377 // because this has no dependence on the interface at this
1378 // point, it needs to be done after we know the interface
1379 // exists, not before.
1380 getDHCPConfigData(asyncResp);
1381
Ed Tanous0f74e642018-11-12 15:17:05 -08001382 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001383 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001384 asyncResp->res.jsonValue["@odata.context"] =
1385 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1386 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1387 asyncResp->res.jsonValue["Description"] =
1388 "Management Network Interface";
1389
1390 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1391 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001392 });
1393 }
1394
1395 void doPatch(crow::Response &res, const crow::Request &req,
1396 const std::vector<std::string> &params) override
1397 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001398 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001399 if (params.size() != 1)
1400 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001401 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001402 return;
1403 }
1404
Ed Tanous4a0cb852018-10-15 07:55:04 -07001405 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001406
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001407 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301408 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001409 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301410 std::optional<nlohmann::json> ipv4Addresses;
1411 std::optional<nlohmann::json> ipv6Addresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001412 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001413 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001414 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001415
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001416 if (!json_util::readJson(
1417 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001418 "IPv6Addresses", ipv6Addresses, "MACAddress", macAddress,
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001419 "StaticNameServers", staticNameServers, "IPv6DefaultGateway",
Jennifer Leeda131a92019-04-24 15:13:55 -07001420 ipv6DefaultGateway, "NameServers", nameServers, "DHCPv4",
1421 dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 {
1423 return;
1424 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301425
Jennifer Leeda131a92019-04-24 15:13:55 -07001426 if (dhcpv4)
1427 {
1428 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1429 }
1430
Ed Tanous4a0cb852018-10-15 07:55:04 -07001431 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001432 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001433 getEthernetIfaceData(
1434 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001435 [this, asyncResp, iface_id, hostname = std::move(hostname),
1436 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001437 ipv4Addresses = std::move(ipv4Addresses),
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001438 ipv6Addresses = std::move(ipv6Addresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001439 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001440 staticNameServers = std::move(staticNameServers),
1441 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001442 const bool &success, const EthernetInterfaceData &ethData,
1443 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001444 if (!success)
1445 {
1446 // ... otherwise return error
1447 // TODO(Pawel)consider distinguish between non existing
1448 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001449 messages::resourceNotFound(asyncResp->res,
1450 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001451 return;
1452 }
1453
Ed Tanous0f74e642018-11-12 15:17:05 -08001454 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1455 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001456
Ed Tanous0627a2c2018-11-29 17:09:23 -08001457 if (hostname)
1458 {
1459 handleHostnamePatch(*hostname, asyncResp);
1460 }
1461
Ratan Guptad5776652019-03-03 08:47:22 +05301462 if (macAddress)
1463 {
1464 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1465 }
1466
Ed Tanous0627a2c2018-11-29 17:09:23 -08001467 if (ipv4Addresses)
1468 {
Ed Tanous537174c2018-12-10 15:09:31 -08001469 // TODO(ed) for some reason the capture of ipv4Addresses
1470 // above is returning a const value, not a non-const value.
1471 // This doesn't really work for us, as we need to be able to
1472 // efficiently move out the intermedia nlohmann::json
1473 // objects. This makes a copy of the structure, and operates
1474 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301475 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001476 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001477 }
1478
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001479 if (nameServers)
1480 {
1481 // Data.Permissions is read-only
1482 messages::propertyNotWritable(asyncResp->res,
1483 "NameServers");
1484 }
1485
Ed Tanous0627a2c2018-11-29 17:09:23 -08001486 if (ipv6Addresses)
1487 {
1488 // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1489 messages::propertyNotWritable(asyncResp->res,
1490 "IPv6Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001491 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001492
1493 if (staticNameServers)
1494 {
1495 handleStaticNameServersPatch(iface_id, *staticNameServers,
1496 asyncResp);
1497 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001498
1499 if (ipv6DefaultGateway)
1500 {
1501 messages::propertyNotWritable(asyncResp->res,
1502 "IPv6DefaultGateway");
1503 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001504 });
1505 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001506};
1507
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001508/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001509 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1510 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001511 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001512class VlanNetworkInterface : public Node
1513{
1514 public:
1515 /*
1516 * Default Constructor
1517 */
1518 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001520 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001521 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001522 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001524 entityPrivileges = {
1525 {boost::beast::http::verb::get, {{"Login"}}},
1526 {boost::beast::http::verb::head, {{"Login"}}},
1527 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1528 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1529 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1530 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001531 }
1532
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001534 void parseInterfaceData(
1535 nlohmann::json &json_response, const std::string &parent_iface_id,
1536 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001537 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001538 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001540 json_response["Id"] = iface_id;
1541 json_response["@odata.id"] =
1542 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1543 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544
Ed Tanous4a0cb852018-10-15 07:55:04 -07001545 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001546 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001547 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001548 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001549 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001550 }
1551
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001552 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553 {
1554 if (!boost::starts_with(iface, parent + "_"))
1555 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556 return false;
1557 }
1558 else
1559 {
1560 return true;
1561 }
1562 }
1563
1564 /**
1565 * Functions triggers appropriate requests on DBus
1566 */
1567 void doGet(crow::Response &res, const crow::Request &req,
1568 const std::vector<std::string> &params) override
1569 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001570 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1571 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001572 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1573 // Check if there is required param, truly entering this shall be
1574 // impossible.
1575 if (params.size() != 2)
1576 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001577 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001579 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001580 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001581
Ed Tanous4a0cb852018-10-15 07:55:04 -07001582 const std::string &parent_iface_id = params[0];
1583 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001584 res.jsonValue["@odata.type"] =
1585 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1586 res.jsonValue["@odata.context"] =
1587 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1588 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001589
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001590 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001591 {
1592 return;
1593 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001594
Ed Tanous1abe55e2018-09-05 08:30:59 -07001595 // Get single eth interface data, and call the below callback for JSON
1596 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001597 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001598 params[1],
1599 [this, asyncResp, parent_iface_id{std::string(params[0])},
1600 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001601 const bool &success, const EthernetInterfaceData &ethData,
1602 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001603 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001604 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001605 parseInterfaceData(asyncResp->res.jsonValue,
1606 parent_iface_id, iface_id, ethData,
1607 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001608 }
1609 else
1610 {
1611 // ... otherwise return error
1612 // TODO(Pawel)consider distinguish between non existing
1613 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001614 messages::resourceNotFound(
1615 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001616 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001617 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001618 }
1619
Ed Tanous1abe55e2018-09-05 08:30:59 -07001620 void doPatch(crow::Response &res, const crow::Request &req,
1621 const std::vector<std::string> &params) override
1622 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001623 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001624 if (params.size() != 2)
1625 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001626 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 return;
1628 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001629
Ed Tanous1abe55e2018-09-05 08:30:59 -07001630 const std::string &parentIfaceId = params[0];
1631 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001632
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001633 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001635 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1636 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637 return;
1638 }
1639
Ed Tanous0627a2c2018-11-29 17:09:23 -08001640 bool vlanEnable = false;
1641 uint64_t vlanId = 0;
1642
1643 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1644 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001645 {
1646 return;
1647 }
1648
1649 // Get single eth interface data, and call the below callback for JSON
1650 // preparation
Sunitha Harish08244d02019-04-01 03:57:25 -05001651 getEthernetIfaceData(params[1], [this, asyncResp,
1652 parentIfaceId{std::string(params[0])},
1653 ifaceId{std::string(params[1])},
1654 &vlanEnable, &vlanId](
1655 const bool &success,
1656 const EthernetInterfaceData
1657 &ethData,
1658 const boost::container::flat_set<
1659 IPv4AddressData> &ipv4Data) {
1660 if (success && !ethData.vlan_id.empty())
1661 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001662 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1663 ifaceId, ethData, ipv4Data);
Sunitha Harish08244d02019-04-01 03:57:25 -05001664 auto callback =
1665 [asyncResp](const boost::system::error_code ec) {
1666 if (ec)
1667 {
1668 messages::internalError(asyncResp->res);
1669 }
1670 };
Ed Tanous1abe55e2018-09-05 08:30:59 -07001671
Sunitha Harish08244d02019-04-01 03:57:25 -05001672 if (vlanEnable == true)
1673 {
1674 crow::connections::systemBus->async_method_call(
1675 std::move(callback), "xyz.openbmc_project.Network",
1676 "/xyz/openbmc_project/network/" + ifaceId,
1677 "org.freedesktop.DBus.Properties", "Set",
1678 "xyz.openbmc_project.Network.VLAN", "Id",
1679 std::variant<uint32_t>(vlanId));
1680 }
1681 else
1682 {
1683 BMCWEB_LOG_DEBUG
1684 << "vlanEnable is false. Deleting the vlan interface";
1685 crow::connections::systemBus->async_method_call(
1686 std::move(callback), "xyz.openbmc_project.Network",
1687 std::string("/xyz/openbmc_project/network/") + ifaceId,
1688 "xyz.openbmc_project.Object.Delete", "Delete");
1689 }
1690 }
1691 else
1692 {
1693 // TODO(Pawel)consider distinguish between non existing
1694 // object, and other errors
1695 messages::resourceNotFound(asyncResp->res,
1696 "VLAN Network Interface", ifaceId);
1697 return;
1698 }
1699 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 }
1701
1702 void doDelete(crow::Response &res, const crow::Request &req,
1703 const std::vector<std::string> &params) override
1704 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001705 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 if (params.size() != 2)
1707 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001708 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 return;
1710 }
1711
1712 const std::string &parentIfaceId = params[0];
1713 const std::string &ifaceId = params[1];
1714
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001715 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001717 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1718 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001719 return;
1720 }
1721
1722 // Get single eth interface data, and call the below callback for JSON
1723 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001724 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001725 params[1],
1726 [this, asyncResp, parentIfaceId{std::string(params[0])},
1727 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001728 const bool &success, const EthernetInterfaceData &ethData,
1729 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001730 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001731 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001732 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1733 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734
Jason M. Billsf12894f2018-10-09 12:45:45 -07001735 auto callback =
1736 [asyncResp](const boost::system::error_code ec) {
1737 if (ec)
1738 {
1739 messages::internalError(asyncResp->res);
1740 }
1741 };
1742 crow::connections::systemBus->async_method_call(
1743 std::move(callback), "xyz.openbmc_project.Network",
1744 std::string("/xyz/openbmc_project/network/") + ifaceId,
1745 "xyz.openbmc_project.Object.Delete", "Delete");
1746 }
1747 else
1748 {
1749 // ... otherwise return error
1750 // TODO(Pawel)consider distinguish between non existing
1751 // object, and other errors
1752 messages::resourceNotFound(
1753 asyncResp->res, "VLAN Network Interface", ifaceId);
1754 }
1755 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001756 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001757};
1758
1759/**
1760 * VlanNetworkInterfaceCollection derived class for delivering
1761 * VLANNetworkInterface Collection Schema
1762 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763class VlanNetworkInterfaceCollection : public Node
1764{
1765 public:
1766 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001767 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001768 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1769 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771 entityPrivileges = {
1772 {boost::beast::http::verb::get, {{"Login"}}},
1773 {boost::beast::http::verb::head, {{"Login"}}},
1774 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1775 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1776 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1777 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001778 }
1779
Ed Tanous1abe55e2018-09-05 08:30:59 -07001780 private:
1781 /**
1782 * Functions triggers appropriate requests on DBus
1783 */
1784 void doGet(crow::Response &res, const crow::Request &req,
1785 const std::vector<std::string> &params) override
1786 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001787 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001788 if (params.size() != 1)
1789 {
1790 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07001791 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001792 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07001793 }
1794
Ed Tanous4a0cb852018-10-15 07:55:04 -07001795 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001796
Ed Tanous4a0cb852018-10-15 07:55:04 -07001797 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001798 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001799 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08001800 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001801 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07001802 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001803 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001805 messages::internalError(asyncResp->res);
1806 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001808
1809 if (iface_list.find(rootInterfaceName) == iface_list.end())
1810 {
1811 messages::resourceNotFound(asyncResp->res,
1812 "VLanNetworkInterfaceCollection",
1813 rootInterfaceName);
1814 return;
1815 }
1816
Ed Tanous0f74e642018-11-12 15:17:05 -08001817 asyncResp->res.jsonValue["@odata.type"] =
1818 "#VLanNetworkInterfaceCollection."
1819 "VLanNetworkInterfaceCollection";
1820 asyncResp->res.jsonValue["@odata.context"] =
1821 "/redfish/v1/$metadata"
1822 "#VLanNetworkInterfaceCollection."
1823 "VLanNetworkInterfaceCollection";
1824 asyncResp->res.jsonValue["Name"] =
1825 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07001826
Jason M. Billsf12894f2018-10-09 12:45:45 -07001827 nlohmann::json iface_array = nlohmann::json::array();
1828
1829 for (const std::string &iface_item : iface_list)
1830 {
1831 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
1832 {
1833 iface_array.push_back(
1834 {{"@odata.id",
1835 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1836 rootInterfaceName + "/VLANs/" + iface_item}});
1837 }
1838 }
1839
Jason M. Billsf12894f2018-10-09 12:45:45 -07001840 asyncResp->res.jsonValue["Members@odata.count"] =
1841 iface_array.size();
1842 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
1843 asyncResp->res.jsonValue["@odata.id"] =
1844 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1845 rootInterfaceName + "/VLANs";
1846 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001848
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849 void doPost(crow::Response &res, const crow::Request &req,
1850 const std::vector<std::string> &params) override
1851 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001852 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 if (params.size() != 1)
1854 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001855 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856 return;
1857 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001858 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001859 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001860 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
1861 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001863 return;
1864 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001865 // Need both vlanId and vlanEnable to service this request
1866 if (!vlanId)
1867 {
1868 messages::propertyMissing(asyncResp->res, "VLANId");
1869 }
1870 if (!vlanEnable)
1871 {
1872 messages::propertyMissing(asyncResp->res, "VLANEnable");
1873 }
1874 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1875 {
1876 return;
1877 }
1878
Ed Tanous4a0cb852018-10-15 07:55:04 -07001879 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07001880 auto callback = [asyncResp](const boost::system::error_code ec) {
1881 if (ec)
1882 {
1883 // TODO(ed) make more consistent error messages based on
1884 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07001885 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001886 return;
1887 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001888 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001889 };
1890 crow::connections::systemBus->async_method_call(
1891 std::move(callback), "xyz.openbmc_project.Network",
1892 "/xyz/openbmc_project/network",
1893 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08001894 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001896};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001897} // namespace redfish