blob: 7dd6f34095a84c199396cff00cec8d757fb49b76 [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/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
81 uint8_t prefixLength;
82
83 bool operator<(const IPv6AddressData &obj) const
84 {
85 return id < obj.id;
86 }
87};
88/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010089 * Structure for keeping basic single Ethernet Interface information
90 * available from DBus
91 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070092struct EthernetInterfaceData
93{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t speed;
95 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053096 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070097 std::string hostname;
98 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -050099 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700100 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500101 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -0800102 std::vector<std::string> nameservers;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100103};
104
Ed Tanous4a0cb852018-10-15 07:55:04 -0700105// Helper function that changes bits netmask notation (i.e. /24)
106// into full dot notation
107inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700109 uint32_t value = 0xffffffff << (32 - bits);
110 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
111 std::to_string((value >> 16) & 0xff) + "." +
112 std::to_string((value >> 8) & 0xff) + "." +
113 std::to_string(value & 0xff);
114 return netmask;
115}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100116
Ed Tanous4a0cb852018-10-15 07:55:04 -0700117inline std::string
118 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
119 bool isIPv4)
120{
121 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700123 return "Static";
124 }
125 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
126 {
127 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700129 return "IPv4LinkLocal";
130 }
131 else
132 {
133 return "LinkLocal";
134 }
135 }
136 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
137 {
138 if (isIPv4)
139 {
140 return "DHCP";
141 }
142 else
143 {
144 return "DHCPv6";
145 }
146 }
147 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
148 {
149 return "SLAAC";
150 }
151 return "";
152}
153
Ed Tanous4c9afe42019-05-03 16:59:57 -0700154inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700155 const GetManagedObjects &dbus_data,
156 EthernetInterfaceData &ethData)
157{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700158 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700159 for (const auto &objpath : dbus_data)
160 {
Ed Tanous029573d2019-02-01 10:57:49 -0800161 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700162 {
Ed Tanous029573d2019-02-01 10:57:49 -0800163 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700164 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700165 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700166 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700168 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700170 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700172 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800173 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700174 if (mac != nullptr)
175 {
176 ethData.mac_address = *mac;
177 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700179 }
180 }
181 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
182 {
183 for (const auto &propertyPair : ifacePair.second)
184 {
185 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800187 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800188 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700189 if (id != nullptr)
190 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500191 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700192 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700194 }
195 }
196 else if (ifacePair.first ==
197 "xyz.openbmc_project.Network.EthernetInterface")
198 {
199 for (const auto &propertyPair : ifacePair.second)
200 {
201 if (propertyPair.first == "AutoNeg")
202 {
203 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800204 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700205 if (auto_neg != nullptr)
206 {
207 ethData.auto_neg = *auto_neg;
208 }
209 }
210 else if (propertyPair.first == "Speed")
211 {
212 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800213 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700214 if (speed != nullptr)
215 {
216 ethData.speed = *speed;
217 }
218 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500219 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700220 {
Ed Tanous029573d2019-02-01 10:57:49 -0800221 const std::vector<std::string> *nameservers =
222 sdbusplus::message::variant_ns::get_if<
223 std::vector<std::string>>(
224 &propertyPair.second);
225 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700226 {
Ed Tanous029573d2019-02-01 10:57:49 -0800227 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700228 }
229 }
manojkiraneda2a133282019-02-19 13:09:43 +0530230 else if (propertyPair.first == "DHCPEnabled")
231 {
232 const bool *DHCPEnabled =
233 std::get_if<bool>(&propertyPair.second);
234 if (DHCPEnabled != nullptr)
235 {
236 ethData.DHCPEnabled = *DHCPEnabled;
237 }
238 }
Ed Tanous029573d2019-02-01 10:57:49 -0800239 }
240 }
241 }
242 // System configuration shows up in the global namespace, so no need
243 // to check eth number
244 if (ifacePair.first ==
245 "xyz.openbmc_project.Network.SystemConfiguration")
246 {
247 for (const auto &propertyPair : ifacePair.second)
248 {
249 if (propertyPair.first == "HostName")
250 {
251 const std::string *hostname =
252 sdbusplus::message::variant_ns::get_if<std::string>(
253 &propertyPair.second);
254 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700255 {
Ed Tanous029573d2019-02-01 10:57:49 -0800256 ethData.hostname = *hostname;
257 }
258 }
259 else if (propertyPair.first == "DefaultGateway")
260 {
261 const std::string *defaultGateway =
262 sdbusplus::message::variant_ns::get_if<std::string>(
263 &propertyPair.second);
264 if (defaultGateway != nullptr)
265 {
266 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700267 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500269 else if (propertyPair.first == "DefaultGateway6")
270 {
271 const std::string *defaultGateway6 =
272 sdbusplus::message::variant_ns::get_if<std::string>(
273 &propertyPair.second);
274 if (defaultGateway6 != nullptr)
275 {
276 ethData.ipv6_default_gateway = *defaultGateway6;
277 }
278 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 }
280 }
281 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700282 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700283 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700284}
285
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500286// Helper function that extracts data for single ethernet ipv6 address
287inline void extractIPV6Data(
288 const std::string &ethiface_id, const GetManagedObjects &dbus_data,
289 boost::container::flat_set<IPv6AddressData> &ipv6_config,
290 boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
291{
292 const std::string ipv6PathStart =
293 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
294
295 // Since there might be several IPv6 configurations aligned with
296 // single ethernet interface, loop over all of them
297 for (const auto &objpath : dbus_data)
298 {
299 // Check if proper pattern for object path appears
300 if (boost::starts_with(objpath.first.str, ipv6PathStart))
301 {
302 for (auto &interface : objpath.second)
303 {
304 if (interface.first == "xyz.openbmc_project.Network.IP")
305 {
306 // Instance IPv6AddressData structure, and set as
307 // appropriate
308 std::pair<
309 boost::container::flat_set<IPv6AddressData>::iterator,
310 bool>
311 it = ipv6_config.insert(
312 {objpath.first.str.substr(ipv6PathStart.size())});
313 IPv6AddressData &ipv6_address = *it.first;
314 for (auto &property : interface.second)
315 {
316 if (property.first == "Address")
317 {
318 const std::string *address =
319 std::get_if<std::string>(&property.second);
320 if (address != nullptr)
321 {
322 ipv6_address.address = *address;
323 }
324 }
325 else if (property.first == "Origin")
326 {
327 const std::string *origin =
328 std::get_if<std::string>(&property.second);
329 if (origin != nullptr)
330 {
331 ipv6_address.origin =
332 translateAddressOriginDbusToRedfish(*origin,
333 false);
334 }
335 }
336 else if (property.first == "PrefixLength")
337 {
338 const uint8_t *prefix =
339 std::get_if<uint8_t>(&property.second);
340 if (prefix != nullptr)
341 {
342 ipv6_address.prefixLength = *prefix;
343 }
344 }
345 else
346 {
347 BMCWEB_LOG_ERROR
348 << "Got extra property: " << property.first
349 << " on the " << objpath.first.str << " object";
350 }
351 }
352 if (ipv6_address.origin == "Static")
353 {
354 std::pair<boost::container::flat_set<
355 IPv6AddressData>::iterator,
356 bool>
357 iter = ipv6_static_config.insert(
358 {objpath.first.str.substr(
359 ipv6PathStart.size())});
360 IPv6AddressData &ipv6_static_address = *iter.first;
361
362 ipv6_static_address.address = ipv6_address.address;
363 ipv6_static_address.prefixLength =
364 ipv6_address.prefixLength;
365 }
366 }
367 }
368 }
369 }
370}
371
Ed Tanous4a0cb852018-10-15 07:55:04 -0700372// Helper function that extracts data for single ethernet ipv4 address
373inline void
374 extractIPData(const std::string &ethiface_id,
375 const GetManagedObjects &dbus_data,
376 boost::container::flat_set<IPv4AddressData> &ipv4_config)
377{
378 const std::string ipv4PathStart =
379 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
380
381 // Since there might be several IPv4 configurations aligned with
382 // single ethernet interface, loop over all of them
383 for (const auto &objpath : dbus_data)
384 {
385 // Check if proper pattern for object path appears
386 if (boost::starts_with(objpath.first.str, ipv4PathStart))
387 {
388 for (auto &interface : objpath.second)
389 {
390 if (interface.first == "xyz.openbmc_project.Network.IP")
391 {
392 // Instance IPv4AddressData structure, and set as
393 // appropriate
394 std::pair<
395 boost::container::flat_set<IPv4AddressData>::iterator,
396 bool>
397 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000398 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700399 IPv4AddressData &ipv4_address = *it.first;
400 for (auto &property : interface.second)
401 {
402 if (property.first == "Address")
403 {
404 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800405 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700406 if (address != nullptr)
407 {
408 ipv4_address.address = *address;
409 }
410 }
411 else if (property.first == "Gateway")
412 {
413 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800414 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700415 if (gateway != nullptr)
416 {
417 ipv4_address.gateway = *gateway;
418 }
419 }
420 else if (property.first == "Origin")
421 {
422 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800423 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700424 if (origin != nullptr)
425 {
426 ipv4_address.origin =
427 translateAddressOriginDbusToRedfish(*origin,
428 true);
429 }
430 }
431 else if (property.first == "PrefixLength")
432 {
433 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800434 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700435 if (mask != nullptr)
436 {
437 // convert it to the string
438 ipv4_address.netmask = getNetmask(*mask);
439 }
440 }
441 else
442 {
443 BMCWEB_LOG_ERROR
444 << "Got extra property: " << property.first
445 << " on the " << objpath.first.str << " object";
446 }
447 }
448 // Check if given address is local, or global
449 ipv4_address.linktype =
450 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700451 ? LinkType::Local
452 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700453 }
454 }
455 }
456 }
457}
458
459/**
460 * @brief Sets given Id on the given VLAN interface through D-Bus
461 *
462 * @param[in] ifaceId Id of VLAN interface that should be modified
463 * @param[in] inputVlanId New ID of the VLAN
464 * @param[in] callback Function that will be called after the operation
465 *
466 * @return None.
467 */
468template <typename CallbackFunc>
469void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
470 CallbackFunc &&callback)
471{
472 crow::connections::systemBus->async_method_call(
473 callback, "xyz.openbmc_project.Network",
474 std::string("/xyz/openbmc_project/network/") + ifaceId,
475 "org.freedesktop.DBus.Properties", "Set",
476 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800477 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700478}
479
480/**
481 * @brief Helper function that verifies IP address to check if it is in
482 * proper format. If bits pointer is provided, also calculates active
483 * bit count for Subnet Mask.
484 *
485 * @param[in] ip IP that will be verified
486 * @param[out] bits Calculated mask in bits notation
487 *
488 * @return true in case of success, false otherwise
489 */
490inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
491 uint8_t *bits = nullptr)
492{
493 std::vector<std::string> bytesInMask;
494
495 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496
497 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700498 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700500 return false;
501 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502
Ed Tanous4a0cb852018-10-15 07:55:04 -0700503 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700505 *bits = 0;
506 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507
Ed Tanous4a0cb852018-10-15 07:55:04 -0700508 char *endPtr;
509 long previousValue = 255;
510 bool firstZeroInByteHit;
511 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700513 if (byte.empty())
514 {
515 return false;
516 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517
Ed Tanous4a0cb852018-10-15 07:55:04 -0700518 // Use strtol instead of stroi to avoid exceptions
519 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520
Ed Tanous4a0cb852018-10-15 07:55:04 -0700521 // endPtr should point to the end of the string, otherwise given string
522 // is not 100% number
523 if (*endPtr != '\0')
524 {
525 return false;
526 }
527
528 // Value should be contained in byte
529 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
531 return false;
532 }
533
534 if (bits != nullptr)
535 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700536 // Mask has to be continuous between bytes
537 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 {
539 return false;
540 }
541
Ed Tanous4a0cb852018-10-15 07:55:04 -0700542 // Mask has to be continuous inside bytes
543 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544
Ed Tanous4a0cb852018-10-15 07:55:04 -0700545 // Count bits
546 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700550 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700552 // Continuity not preserved
553 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700554 }
555 else
556 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700557 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 }
559 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 else
561 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700562 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700564 }
565 }
566
567 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 }
569
Ed Tanous4a0cb852018-10-15 07:55:04 -0700570 return true;
571}
572
573/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000574 * @brief Changes IPv4 address type property (Address, Gateway)
575 *
576 * @param[in] ifaceId Id of interface whose IP should be modified
577 * @param[in] ipIdx Index of IP in input array that should be modified
578 * @param[in] ipHash DBus Hash id of modified IP
579 * @param[in] name Name of field in JSON representation
580 * @param[in] newValue New value that should be written
581 * @param[io] asyncResp Response object that will be returned to client
582 *
583 * @return true if give IP is valid and has been sent do D-Bus, false
584 * otherwise
585 */
586inline void changeIPv4AddressProperty(
587 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
588 const std::string &name, const std::string &newValue,
589 const std::shared_ptr<AsyncResp> asyncResp)
590{
591 auto callback = [asyncResp, ipIdx, name{std::string(name)},
592 newValue{std::move(newValue)}](
593 const boost::system::error_code ec) {
594 if (ec)
595 {
596 messages::internalError(asyncResp->res);
597 }
598 else
599 {
600 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
601 }
602 };
603
604 crow::connections::systemBus->async_method_call(
605 std::move(callback), "xyz.openbmc_project.Network",
606 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
607 "org.freedesktop.DBus.Properties", "Set",
608 "xyz.openbmc_project.Network.IP", name,
609 std::variant<std::string>(newValue));
610}
611
612/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700613 * @brief Modifies SubnetMask for given IP
614 *
615 * @param[in] ifaceId Id of interface whose IP should be modified
616 * @param[in] ipIdx Index of IP in input array that should be
617 * modified
618 * @param[in] ipHash DBus Hash id of modified IP
619 * @param[in] newValueStr Mask in dot notation as string
620 * @param[in] newValue Mask as PrefixLength in bitcount
621 * @param[io] asyncResp Response object that will be returned to client
622 *
623 * @return None
624 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000625inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700626 const std::string &ipHash,
627 const std::string &newValueStr,
628 uint8_t &newValue,
629 std::shared_ptr<AsyncResp> asyncResp)
630{
631 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
632 const boost::system::error_code ec) {
633 if (ec)
634 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800635 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700636 }
637 else
638 {
639 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
640 newValueStr;
641 }
642 };
643
644 crow::connections::systemBus->async_method_call(
645 std::move(callback), "xyz.openbmc_project.Network",
646 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
647 "org.freedesktop.DBus.Properties", "Set",
648 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800649 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700650}
651
652/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700653 * @brief Deletes given IPv4
654 *
655 * @param[in] ifaceId Id of interface whose IP should be deleted
656 * @param[in] ipIdx Index of IP in input array that should be deleted
657 * @param[in] ipHash DBus Hash id of IP that should be deleted
658 * @param[io] asyncResp Response object that will be returned to client
659 *
660 * @return None
661 */
662inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
663 unsigned int ipIdx,
664 const std::shared_ptr<AsyncResp> asyncResp)
665{
666 crow::connections::systemBus->async_method_call(
667 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 if (ec)
669 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800670 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100671 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700672 else
673 {
674 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
675 }
676 },
677 "xyz.openbmc_project.Network",
678 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
679 "xyz.openbmc_project.Object.Delete", "Delete");
680}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681
Ed Tanous4a0cb852018-10-15 07:55:04 -0700682/**
683 * @brief Creates IPv4 with given data
684 *
685 * @param[in] ifaceId Id of interface whose IP should be deleted
686 * @param[in] ipIdx Index of IP in input array that should be deleted
687 * @param[in] ipHash DBus Hash id of IP that should be deleted
688 * @param[io] asyncResp Response object that will be returned to client
689 *
690 * @return None
691 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000692inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
693 uint8_t subnetMask, const std::string &gateway,
694 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700695 std::shared_ptr<AsyncResp> asyncResp)
696{
Ed Tanous43b761d2019-02-13 20:10:56 -0800697 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700698 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800700 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 };
703
Ed Tanous4a0cb852018-10-15 07:55:04 -0700704 crow::connections::systemBus->async_method_call(
705 std::move(createIpHandler), "xyz.openbmc_project.Network",
706 "/xyz/openbmc_project/network/" + ifaceId,
707 "xyz.openbmc_project.Network.IP.Create", "IP",
708 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
709 gateway);
710}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500711
712/**
713 * @brief Deletes given IPv6
714 *
715 * @param[in] ifaceId Id of interface whose IP should be deleted
716 * @param[in] ipHash DBus Hash id of IP that should be deleted
717 * @param[in] ipIdx Index of IP in input array that should be deleted
718 * @param[io] asyncResp Response object that will be returned to client
719 *
720 * @return None
721 */
722inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
723 unsigned int ipIdx,
724 const std::shared_ptr<AsyncResp> asyncResp)
725{
726 crow::connections::systemBus->async_method_call(
727 [ipIdx, asyncResp](const boost::system::error_code ec) {
728 if (ec)
729 {
730 messages::internalError(asyncResp->res);
731 }
732 else
733 {
734 asyncResp->res.jsonValue["IPv6StaticAddresses"][ipIdx] =
735 nullptr;
736 }
737 },
738 "xyz.openbmc_project.Network",
739 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
740 "xyz.openbmc_project.Object.Delete", "Delete");
741}
742
743/**
744 * @brief Creates IPv6 with given data
745 *
746 * @param[in] ifaceId Id of interface whose IP should be added
747 * @param[in] ipIdx Index of IP in input array that should be added
748 * @param[in] prefixLength Prefix length that needs to be added
749 * @param[in] address IP address that needs to be added
750 * @param[io] asyncResp Response object that will be returned to client
751 *
752 * @return None
753 */
754inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
755 uint8_t prefixLength, const std::string &address,
756 std::shared_ptr<AsyncResp> asyncResp)
757{
758 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
759 if (ec)
760 {
761 messages::internalError(asyncResp->res);
762 }
763 };
764 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
765 // does not have assosiated gateway property
766 crow::connections::systemBus->async_method_call(
767 std::move(createIpHandler), "xyz.openbmc_project.Network",
768 "/xyz/openbmc_project/network/" + ifaceId,
769 "xyz.openbmc_project.Network.IP.Create", "IP",
770 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
771 "");
772}
773
manojkiraneda2a133282019-02-19 13:09:43 +0530774using GetAllPropertiesType =
775 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
776
777inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
778{
779 auto getConfig = [asyncResp](const boost::system::error_code error_code,
780 const GetAllPropertiesType &dbus_data) {
781 if (error_code)
782 {
783 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
784 messages::internalError(asyncResp->res);
785 return;
786 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500787 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530788 for (const auto &property : dbus_data)
789 {
790 auto value =
791 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
792
793 if (value == nullptr)
794 {
795 continue;
796 }
797 if (property.first == "DNSEnabled")
798 {
799 DHCPConfigTypeJson["UseDNSServers"] = *value;
800 }
801 else if (property.first == "HostNameEnabled")
802 {
803 DHCPConfigTypeJson["UseDomainName"] = *value;
804 }
805 else if (property.first == "NTPEnabled")
806 {
807 DHCPConfigTypeJson["UseNTPServers"] = *value;
808 }
809 }
810 };
811 crow::connections::systemBus->async_method_call(
812 std::move(getConfig), "xyz.openbmc_project.Network",
813 "/xyz/openbmc_project/network/config/dhcp",
814 "org.freedesktop.DBus.Properties", "GetAll",
815 "xyz.openbmc_project.Network.DHCPConfiguration");
816}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817
Ed Tanous4a0cb852018-10-15 07:55:04 -0700818/**
819 * Function that retrieves all properties for given Ethernet Interface
820 * Object
821 * from EntityManager Network Manager
822 * @param ethiface_id a eth interface id to query on DBus
823 * @param callback a function that shall be called to convert Dbus output
824 * into JSON
825 */
826template <typename CallbackFunc>
827void getEthernetIfaceData(const std::string &ethiface_id,
828 CallbackFunc &&callback)
829{
830 crow::connections::systemBus->async_method_call(
831 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
832 const boost::system::error_code error_code,
833 const GetManagedObjects &resp) {
834 EthernetInterfaceData ethData{};
835 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500836 boost::container::flat_set<IPv6AddressData> ipv6Data;
837 boost::container::flat_set<IPv6AddressData> ipv6StaticData;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700838
839 if (error_code)
840 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500841 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700842 return;
843 }
844
Ed Tanous4c9afe42019-05-03 16:59:57 -0700845 bool found =
846 extractEthernetInterfaceData(ethiface_id, resp, ethData);
847 if (!found)
848 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500849 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700850 return;
851 }
852
Ed Tanous4a0cb852018-10-15 07:55:04 -0700853 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700854 // Fix global GW
855 for (IPv4AddressData &ipv4 : ipv4Data)
856 {
857 if ((ipv4.linktype == LinkType::Global) &&
858 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700860 ipv4.gateway = ethData.default_gateway;
861 }
862 }
863
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500864 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700865 // Finally make a callback with usefull data
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500866 callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700867 },
868 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
869 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
870};
871
872/**
873 * Function that retrieves all Ethernet Interfaces available through Network
874 * Manager
875 * @param callback a function that shall be called to convert Dbus output
876 * into JSON.
877 */
878template <typename CallbackFunc>
879void getEthernetIfaceList(CallbackFunc &&callback)
880{
881 crow::connections::systemBus->async_method_call(
882 [callback{std::move(callback)}](
883 const boost::system::error_code error_code,
884 GetManagedObjects &resp) {
885 // Callback requires vector<string> to retrieve all available
886 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700887 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700888 iface_list.reserve(resp.size());
889 if (error_code)
890 {
891 callback(false, iface_list);
892 return;
893 }
894
895 // Iterate over all retrieved ObjectPaths.
896 for (const auto &objpath : resp)
897 {
898 // And all interfaces available for certain ObjectPath.
899 for (const auto &interface : objpath.second)
900 {
901 // If interface is
902 // xyz.openbmc_project.Network.EthernetInterface, this is
903 // what we're looking for.
904 if (interface.first ==
905 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700907 // Cut out everyting until last "/", ...
908 const std::string &iface_id = objpath.first.str;
909 std::size_t last_pos = iface_id.rfind("/");
910 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700912 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700913 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 }
915 }
916 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700917 }
918 // Finally make a callback with useful data
919 callback(true, iface_list);
920 },
921 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
922 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100923};
924
925/**
926 * EthernetCollection derived class for delivering Ethernet Collection Schema
927 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700928class EthernetCollection : public Node
929{
930 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700931 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700933 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 entityPrivileges = {
936 {boost::beast::http::verb::get, {{"Login"}}},
937 {boost::beast::http::verb::head, {{"Login"}}},
938 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
939 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
940 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
941 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
942 }
943
944 private:
945 /**
946 * Functions triggers appropriate requests on DBus
947 */
948 void doGet(crow::Response &res, const crow::Request &req,
949 const std::vector<std::string> &params) override
950 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800951 res.jsonValue["@odata.type"] =
952 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
953 res.jsonValue["@odata.context"] =
954 "/redfish/v1/"
955 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
956 res.jsonValue["@odata.id"] =
957 "/redfish/v1/Managers/bmc/EthernetInterfaces";
958 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
959 res.jsonValue["Description"] =
960 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700961 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700962 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700964 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700965 [asyncResp](
966 const bool &success,
967 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700968 if (!success)
969 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700970 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700971 return;
972 }
973
Ed Tanous4c9afe42019-05-03 16:59:57 -0700974 nlohmann::json &iface_array =
975 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700976 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500977 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700978 for (const std::string &iface_item : iface_list)
979 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500980 std::size_t found = iface_item.find(tag);
981 if (found == std::string::npos)
982 {
983 iface_array.push_back(
984 {{"@odata.id",
985 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
986 iface_item}});
987 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700988 }
989
Ed Tanous4c9afe42019-05-03 16:59:57 -0700990 asyncResp->res.jsonValue["Members@odata.count"] =
991 iface_array.size();
992 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700993 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700994 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700995 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100996};
997
998/**
999 * EthernetInterface derived class for delivering Ethernet Schema
1000 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001001class EthernetInterface : public Node
1002{
1003 public:
1004 /*
1005 * Default Constructor
1006 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001007 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001009 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 std::string())
1011 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 entityPrivileges = {
1013 {boost::beast::http::verb::get, {{"Login"}}},
1014 {boost::beast::http::verb::head, {{"Login"}}},
1015 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1016 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1017 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1018 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001019 }
1020
Ed Tanous1abe55e2018-09-05 08:30:59 -07001021 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001022 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001023 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001024 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001025 asyncResp->res.jsonValue["HostName"] = hostname;
1026 crow::connections::systemBus->async_method_call(
1027 [asyncResp](const boost::system::error_code ec) {
1028 if (ec)
1029 {
1030 messages::internalError(asyncResp->res);
1031 }
1032 },
1033 "xyz.openbmc_project.Network",
1034 "/xyz/openbmc_project/network/config",
1035 "org.freedesktop.DBus.Properties", "Set",
1036 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001037 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001038 }
1039
Ratan Guptad5776652019-03-03 08:47:22 +05301040 void handleMACAddressPatch(const std::string &ifaceId,
1041 const std::string &macAddress,
1042 const std::shared_ptr<AsyncResp> &asyncResp)
1043 {
1044 crow::connections::systemBus->async_method_call(
1045 [asyncResp, macAddress](const boost::system::error_code ec) {
1046 if (ec)
1047 {
1048 messages::internalError(asyncResp->res);
1049 return;
1050 }
1051 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
1052 },
1053 "xyz.openbmc_project.Network",
1054 "/xyz/openbmc_project/network/" + ifaceId,
1055 "org.freedesktop.DBus.Properties", "Set",
1056 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1057 std::variant<std::string>(macAddress));
1058 }
Jennifer Leeda131a92019-04-24 15:13:55 -07001059 void setDHCPEnabled(const std::string &ifaceId,
1060 const std::string &propertyName, const bool &value,
1061 const std::shared_ptr<AsyncResp> asyncResp)
1062 {
1063 crow::connections::systemBus->async_method_call(
1064 [asyncResp](const boost::system::error_code ec) {
1065 if (ec)
1066 {
1067 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1068 messages::internalError(asyncResp->res);
1069 return;
1070 }
1071 },
1072 "xyz.openbmc_project.Network",
1073 "/xyz/openbmc_project/network/" + ifaceId,
1074 "org.freedesktop.DBus.Properties", "Set",
1075 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1076 std::variant<bool>{value});
1077 }
1078 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1079 const std::shared_ptr<AsyncResp> asyncResp)
1080 {
1081 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1082 crow::connections::systemBus->async_method_call(
1083 [asyncResp](const boost::system::error_code ec) {
1084 if (ec)
1085 {
1086 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1087 messages::internalError(asyncResp->res);
1088 return;
1089 }
1090 },
1091 "xyz.openbmc_project.Network",
1092 "/xyz/openbmc_project/network/config/dhcp",
1093 "org.freedesktop.DBus.Properties", "Set",
1094 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1095 std::variant<bool>{value});
1096 }
Ratan Guptad5776652019-03-03 08:47:22 +05301097
Jennifer Leeda131a92019-04-24 15:13:55 -07001098 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1099 const std::shared_ptr<AsyncResp> asyncResp)
1100 {
1101 std::optional<bool> dhcpEnabled;
1102 std::optional<bool> useDNSServers;
1103 std::optional<bool> useDomainName;
1104 std::optional<bool> useNTPServers;
1105
1106 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1107 dhcpEnabled, "UseDNSServers", useDNSServers,
1108 "UseDomainName", useDomainName,
1109 "UseNTPServers", useNTPServers))
1110 {
1111 return;
1112 }
1113
1114 if (dhcpEnabled)
1115 {
1116 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1117 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1118 }
1119
1120 if (useDNSServers)
1121 {
1122 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1123 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1124 }
1125
1126 if (useDomainName)
1127 {
1128 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1129 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1130 }
1131
1132 if (useNTPServers)
1133 {
1134 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1135 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1136 }
1137 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001138 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301139 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001140 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1141 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001142 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301143 if (!input.is_array())
1144 {
1145 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1146 "IPv4Addresses");
1147 return;
1148 }
1149
Ed Tanous4a0cb852018-10-15 07:55:04 -07001150 int entryIdx = 0;
1151 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1152 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001153 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001154 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001155 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001156 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001157
Ratan Guptaf476acb2019-03-02 16:46:57 +05301158 if (thisJson.is_null())
1159 {
1160 if (thisData != ipv4Data.end())
1161 {
1162 deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
1163 thisData++;
1164 }
1165 else
1166 {
1167 messages::propertyValueFormatError(
1168 asyncResp->res, input.dump(), pathString);
1169 return;
1170 // TODO(ratagupt) Not sure about the property where value is
1171 // list and if unable to update one of the
1172 // list value then should we proceed further or
1173 // break there, would ask in the redfish forum
1174 // till then we stop processing the next list item.
1175 }
1176 entryIdx++;
1177 continue; // not an error as per the redfish spec.
1178 }
1179
Ratan Gupta9474b372019-03-01 15:13:37 +05301180 if (thisJson.empty())
1181 {
1182 if (thisData != ipv4Data.end())
1183 {
1184 thisData++;
1185 }
1186 else
1187 {
1188 messages::propertyMissing(asyncResp->res,
1189 pathString + "/Address");
1190 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301191 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301192 // list and if unable to update one of the
1193 // list value then should we proceed further or
1194 // break there, would ask in the redfish forum
1195 // till then we stop processing the next list item.
1196 }
1197 entryIdx++;
1198 continue; // not an error as per the redfish spec.
1199 }
1200
Ed Tanous537174c2018-12-10 15:09:31 -08001201 std::optional<std::string> address;
Ed Tanous537174c2018-12-10 15:09:31 -08001202 std::optional<std::string> subnetMask;
1203 std::optional<std::string> gateway;
1204
1205 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
Johnathan Mantey7e27d832019-06-11 10:31:56 -07001206 address, "SubnetMask", subnetMask,
1207 "Gateway", gateway))
Ed Tanous537174c2018-12-10 15:09:31 -08001208 {
1209 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001210 }
1211
Ed Tanous537174c2018-12-10 15:09:31 -08001212 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001213 {
Ed Tanous537174c2018-12-10 15:09:31 -08001214 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001215 {
Ed Tanous537174c2018-12-10 15:09:31 -08001216 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001217 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001218 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001219 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001221
Ed Tanous537174c2018-12-10 15:09:31 -08001222 uint8_t prefixLength = 0;
1223 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001224 {
Ed Tanous537174c2018-12-10 15:09:31 -08001225 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001226 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001227 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001228 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001229 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001230 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001231 }
1232 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001233
Ed Tanous537174c2018-12-10 15:09:31 -08001234 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001235 {
Ed Tanous537174c2018-12-10 15:09:31 -08001236 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001237 {
Ed Tanous537174c2018-12-10 15:09:31 -08001238 messages::propertyValueFormatError(asyncResp->res, *gateway,
1239 pathString + "/Gateway");
1240 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001241 }
1242 }
1243
Ratan Guptaf476acb2019-03-02 16:46:57 +05301244 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001245 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001246 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301247 // Apply changes
1248 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001249 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301250 auto callback = [asyncResp, entryIdx,
1251 address{std::string(*address)}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001252 const boost::system::error_code ec) {
1253 if (ec)
1254 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001255 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001256 return;
1257 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301258 asyncResp->res
1259 .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1260 std::move(address);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001261 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301262
Ed Tanous4a0cb852018-10-15 07:55:04 -07001263 crow::connections::systemBus->async_method_call(
1264 std::move(callback), "xyz.openbmc_project.Network",
1265 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1266 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301267 "org.freedesktop.DBus.Properties", "Set",
1268 "xyz.openbmc_project.Network.IP", "Address",
1269 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001270 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301271
1272 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001273 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301274 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1275 thisData->id, *subnetMask,
1276 prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001277 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301278
Ratan Guptaf476acb2019-03-02 16:46:57 +05301279 if (gateway)
1280 {
1281 auto callback = [asyncResp, entryIdx,
1282 gateway{std::string(*gateway)}](
1283 const boost::system::error_code ec) {
1284 if (ec)
1285 {
1286 messages::internalError(asyncResp->res);
1287 return;
1288 }
1289 asyncResp->res
1290 .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1291 std::move(gateway);
1292 };
1293
1294 crow::connections::systemBus->async_method_call(
1295 std::move(callback), "xyz.openbmc_project.Network",
1296 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1297 thisData->id,
1298 "org.freedesktop.DBus.Properties", "Set",
1299 "xyz.openbmc_project.Network.IP", "Gateway",
1300 std::variant<std::string>(*gateway));
1301 }
1302
Ed Tanous4a0cb852018-10-15 07:55:04 -07001303 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001304 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001305 else
1306 {
1307 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001308 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001309 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001310 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001311 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001312 continue;
1313 }
1314
Ed Tanous537174c2018-12-10 15:09:31 -08001315 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001316 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001317 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001318 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001319 continue;
1320 }
1321
Ed Tanous537174c2018-12-10 15:09:31 -08001322 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001323 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001324 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001325 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001326 continue;
1327 }
1328
Ed Tanousb01bf292019-03-25 19:25:26 +00001329 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1330 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301331
1332 nlohmann::json &ipv4AddressJson =
1333 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1334 ipv4AddressJson["Address"] = *address;
1335 ipv4AddressJson["SubnetMask"] = *subnetMask;
1336 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001337 }
1338 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001339 }
1340 }
1341
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001342 void handleStaticNameServersPatch(
1343 const std::string &ifaceId,
1344 const std::vector<std::string> &updatedStaticNameServers,
1345 const std::shared_ptr<AsyncResp> &asyncResp)
1346 {
1347 crow::connections::systemBus->async_method_call(
1348 [asyncResp,
1349 updatedStaticNameServers](const boost::system::error_code ec) {
1350 if (ec)
1351 {
1352 messages::internalError(asyncResp->res);
1353 return;
1354 }
1355 asyncResp->res.jsonValue["NameServers"] =
1356 updatedStaticNameServers;
1357 asyncResp->res.jsonValue["StaticNameServers"] =
1358 updatedStaticNameServers;
1359 },
1360 "xyz.openbmc_project.Network",
1361 "/xyz/openbmc_project/network/" + ifaceId,
1362 "org.freedesktop.DBus.Properties", "Set",
1363 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1364 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1365 }
1366
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001367 void handleIPv6StaticAddressesPatch(
1368 const std::string &ifaceId, nlohmann::json &input,
1369 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1370 const std::shared_ptr<AsyncResp> asyncResp)
1371 {
1372 if (!input.is_array())
1373 {
1374 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1375 "IPv6StaticAddresses");
1376 return;
1377 }
1378
1379 int entryIdx = 0;
1380 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1381 ipv6StaticData.begin();
1382 for (nlohmann::json &thisJson : input)
1383 {
1384 std::string pathString =
1385 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1386
1387 if (thisJson.is_null())
1388 {
1389 if (thisData != ipv6StaticData.end())
1390 {
1391 deleteIPv6(ifaceId, thisData->id, entryIdx, asyncResp);
1392 thisData++;
1393 }
1394 else
1395 {
1396 messages::propertyValueFormatError(
1397 asyncResp->res, input.dump(), pathString);
1398 return;
1399 }
1400 entryIdx++;
1401 continue;
1402 }
1403
1404 if (thisJson.empty())
1405 {
1406 if (thisData != ipv6StaticData.end())
1407 {
1408 thisData++;
1409 }
1410 else
1411 {
1412 messages::propertyMissing(asyncResp->res,
1413 pathString + "/Address");
1414 return;
1415 }
1416 entryIdx++;
1417 continue;
1418 }
1419
1420 std::optional<std::string> address;
1421 std::optional<uint8_t> prefixLength;
1422
1423 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1424 address, "PrefixLength", prefixLength))
1425 {
1426 return;
1427 }
1428
1429 // if IP address exist then modify it.
1430 if (thisData != ipv6StaticData.end())
1431 {
1432 // Apply changes
1433 if (address)
1434 {
1435 auto callback = [asyncResp, entryIdx,
1436 address{std::string(*address)}](
1437 const boost::system::error_code ec) {
1438 if (ec)
1439 {
1440 messages::internalError(asyncResp->res);
1441 return;
1442 }
1443 asyncResp->res.jsonValue["IPv6StaticAddresses"]
1444 [entryIdx]["Address"] =
1445 std::move(address);
1446 };
1447
1448 crow::connections::systemBus->async_method_call(
1449 std::move(callback), "xyz.openbmc_project.Network",
1450 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1451 thisData->id,
1452 "org.freedesktop.DBus.Properties", "Set",
1453 "xyz.openbmc_project.Network.IP", "Address",
1454 std::variant<std::string>(*address));
1455 }
1456
1457 if (prefixLength)
1458 {
1459 auto callback = [asyncResp, entryIdx,
1460 prefixLength{uint8_t(*prefixLength)}](
1461 const boost::system::error_code ec) {
1462 if (ec)
1463 {
1464 messages::internalError(asyncResp->res);
1465 return;
1466 }
1467 asyncResp->res.jsonValue["IPv6StaticAddresses"]
1468 [entryIdx]["PrefixLength"] =
1469 std::move(prefixLength);
1470 };
1471
1472 crow::connections::systemBus->async_method_call(
1473 std::move(callback), "xyz.openbmc_project.Network",
1474 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1475 thisData->id,
1476 "org.freedesktop.DBus.Properties", "Set",
1477 "xyz.openbmc_project.Network.IP", "PrefixLength",
1478 std::variant<uint8_t>(*prefixLength));
1479 }
1480
1481 thisData++;
1482 }
1483 else
1484 {
1485 // Create IPv6 with provided data
1486
1487 if (!prefixLength)
1488 {
1489 messages::propertyMissing(asyncResp->res,
1490 pathString + "/PrefixLength");
1491 continue;
1492 }
1493
1494 if (!address)
1495 {
1496 messages::propertyMissing(asyncResp->res,
1497 pathString + "/Address");
1498 continue;
1499 }
1500
1501 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1502 asyncResp);
1503
1504 nlohmann::json &ipv6StaticAddressJson =
1505 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1506 ipv6StaticAddressJson["Address"] = *address;
1507 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1508 }
1509 entryIdx++;
1510 }
1511 }
1512
Ed Tanous0f74e642018-11-12 15:17:05 -08001513 void parseInterfaceData(
1514 nlohmann::json &json_response, const std::string &iface_id,
1515 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001516 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1517 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1518 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001520 json_response["Id"] = iface_id;
1521 json_response["@odata.id"] =
1522 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001523 json_response["InterfaceEnabled"] = true;
1524 if (ethData.speed == 0)
1525 {
1526 json_response["LinkStatus"] = "NoLink";
1527 json_response["Status"] = {
1528 {"Health", "OK"},
1529 {"State", "Disabled"},
1530 };
1531 }
1532 else
1533 {
1534 json_response["LinkStatus"] = "LinkUp";
1535 json_response["Status"] = {
1536 {"Health", "OK"},
1537 {"State", "Enabled"},
1538 };
1539 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001540 json_response["SpeedMbps"] = ethData.speed;
1541 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001542 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301543
Ed Tanous4a0cb852018-10-15 07:55:04 -07001544 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001545 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001546 json_response["HostName"] = ethData.hostname;
1547 }
1548
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001549 json_response["VLANs"] = {
1550 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1551 iface_id + "/VLANs"}};
1552
Ed Tanous029573d2019-02-01 10:57:49 -08001553 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001554 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555
Ed Tanous4a0cb852018-10-15 07:55:04 -07001556 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001557 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001558 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1559 ipv4_array = nlohmann::json::array();
1560 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001562
1563 std::string gatewayStr = ipv4_config.gateway;
1564 if (gatewayStr.empty())
1565 {
1566 gatewayStr = "0.0.0.0";
1567 }
1568
Ed Tanous029573d2019-02-01 10:57:49 -08001569 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1570 {"SubnetMask", ipv4_config.netmask},
1571 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001572 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001575 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001576
1577 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1578 ipv6_array = nlohmann::json::array();
1579 for (auto &ipv6_config : ipv6Data)
1580 {
1581 ipv6_array.push_back({{"Address", ipv6_config.address},
1582 {"PrefixLength", ipv6_config.prefixLength},
1583 {"AddressOrigin", ipv6_config.origin}});
1584 }
1585
1586 nlohmann::json &ipv6_static_array =
1587 json_response["IPv6StaticAddresses"];
1588 ipv6_static_array = nlohmann::json::array();
1589 for (auto &ipv6_static_config : ipv6StaticData)
1590 {
1591 ipv6_static_array.push_back(
1592 {{"Address", ipv6_static_config.address},
1593 {"PrefixLength", ipv6_static_config.prefixLength}});
1594 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001595 }
1596
1597 /**
1598 * Functions triggers appropriate requests on DBus
1599 */
1600 void doGet(crow::Response &res, const crow::Request &req,
1601 const std::vector<std::string> &params) override
1602 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001603 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001604 if (params.size() != 1)
1605 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001606 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001607 return;
1608 }
1609
Ed Tanous4a0cb852018-10-15 07:55:04 -07001610 getEthernetIfaceData(
1611 params[0],
1612 [this, asyncResp, iface_id{std::string(params[0])}](
1613 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001614 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1615 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1616 const boost::container::flat_set<IPv6AddressData>
1617 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001618 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001619 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001620 // TODO(Pawel)consider distinguish between non existing
1621 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001622 messages::resourceNotFound(asyncResp->res,
1623 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001624 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001625 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001626
1627 // because this has no dependence on the interface at this
1628 // point, it needs to be done after we know the interface
1629 // exists, not before.
1630 getDHCPConfigData(asyncResp);
1631
Ed Tanous0f74e642018-11-12 15:17:05 -08001632 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001633 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001634 asyncResp->res.jsonValue["@odata.context"] =
1635 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1636 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1637 asyncResp->res.jsonValue["Description"] =
1638 "Management Network Interface";
1639
1640 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001641 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642 });
1643 }
1644
1645 void doPatch(crow::Response &res, const crow::Request &req,
1646 const std::vector<std::string> &params) override
1647 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001648 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649 if (params.size() != 1)
1650 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001651 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001652 return;
1653 }
1654
Ed Tanous4a0cb852018-10-15 07:55:04 -07001655 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001657 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301658 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001659 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301660 std::optional<nlohmann::json> ipv4Addresses;
1661 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001662 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001663 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001664 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001665 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001666
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001667 if (!json_util::readJson(
1668 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Johnathan Mantey6ca6ac12019-06-10 12:21:31 -07001669 "MACAddress", macAddress, "StaticNameServers",
1670 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
1671 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
1672 nameServers, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 {
1674 return;
1675 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301676
Jennifer Leeda131a92019-04-24 15:13:55 -07001677 if (dhcpv4)
1678 {
1679 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1680 }
1681
Ed Tanous4a0cb852018-10-15 07:55:04 -07001682 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001683 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001684 getEthernetIfaceData(
1685 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001686 [this, asyncResp, iface_id, hostname = std::move(hostname),
1687 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001688 ipv4Addresses = std::move(ipv4Addresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001689 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001690 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001691 staticNameServers = std::move(staticNameServers),
1692 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001693 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001694 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1695 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1696 const boost::container::flat_set<IPv6AddressData>
1697 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001698 if (!success)
1699 {
1700 // ... otherwise return error
1701 // TODO(Pawel)consider distinguish between non existing
1702 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001703 messages::resourceNotFound(asyncResp->res,
1704 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001705 return;
1706 }
1707
Ed Tanous0f74e642018-11-12 15:17:05 -08001708 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001709 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710
Ed Tanous0627a2c2018-11-29 17:09:23 -08001711 if (hostname)
1712 {
1713 handleHostnamePatch(*hostname, asyncResp);
1714 }
1715
Ratan Guptad5776652019-03-03 08:47:22 +05301716 if (macAddress)
1717 {
1718 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1719 }
1720
Ed Tanous0627a2c2018-11-29 17:09:23 -08001721 if (ipv4Addresses)
1722 {
Ed Tanous537174c2018-12-10 15:09:31 -08001723 // TODO(ed) for some reason the capture of ipv4Addresses
1724 // above is returning a const value, not a non-const value.
1725 // This doesn't really work for us, as we need to be able to
1726 // efficiently move out the intermedia nlohmann::json
1727 // objects. This makes a copy of the structure, and operates
1728 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301729 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001730 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001731 }
1732
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001733 if (nameServers)
1734 {
1735 // Data.Permissions is read-only
1736 messages::propertyNotWritable(asyncResp->res,
1737 "NameServers");
1738 }
1739
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001740 if (staticNameServers)
1741 {
1742 handleStaticNameServersPatch(iface_id, *staticNameServers,
1743 asyncResp);
1744 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001745
1746 if (ipv6DefaultGateway)
1747 {
1748 messages::propertyNotWritable(asyncResp->res,
1749 "IPv6DefaultGateway");
1750 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001751
1752 if (ipv6StaticAddresses)
1753 {
1754 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1755 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1756 ipv6StaticData, asyncResp);
1757
1758 // call getEthernetIfaceData to populate updated static
1759 // addresses data to "IPv6Addresses" json collection
1760 getEthernetIfaceData(
1761 iface_id,
1762 [this, asyncResp, iface_id](
1763 const bool &success,
1764 const EthernetInterfaceData &ethData,
1765 const boost::container::flat_set<IPv4AddressData>
1766 &ipv4Data,
1767 const boost::container::flat_set<IPv6AddressData>
1768 &ipv6Data,
1769 const boost::container::flat_set<IPv6AddressData>
1770 &ipv6StaticData) {
1771 if (!success)
1772 {
1773 messages::resourceNotFound(asyncResp->res,
1774 "Ethernet Interface",
1775 iface_id);
1776 return;
1777 }
1778
1779 parseInterfaceData(asyncResp->res.jsonValue,
1780 iface_id, ethData, ipv4Data,
1781 ipv6Data, ipv6StaticData);
1782 });
1783 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 });
1785 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001786};
1787
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001788/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001789 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1790 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001791 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001792class VlanNetworkInterface : public Node
1793{
1794 public:
1795 /*
1796 * Default Constructor
1797 */
1798 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001799 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001800 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001801 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001802 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 entityPrivileges = {
1805 {boost::beast::http::verb::get, {{"Login"}}},
1806 {boost::beast::http::verb::head, {{"Login"}}},
1807 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1808 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1809 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1810 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001811 }
1812
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001814 void parseInterfaceData(
1815 nlohmann::json &json_response, const std::string &parent_iface_id,
1816 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001817 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1818 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1819 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001822 json_response["Id"] = iface_id;
1823 json_response["@odata.id"] =
1824 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1825 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826
Ed Tanous4a0cb852018-10-15 07:55:04 -07001827 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001828 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001829 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001830 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001831 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001832 }
1833
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001834 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 {
1836 if (!boost::starts_with(iface, parent + "_"))
1837 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001838 return false;
1839 }
1840 else
1841 {
1842 return true;
1843 }
1844 }
1845
1846 /**
1847 * Functions triggers appropriate requests on DBus
1848 */
1849 void doGet(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);
1853 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1855 // Check if there is required param, truly entering this shall be
1856 // impossible.
1857 if (params.size() != 2)
1858 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001859 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001860 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001861 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001863
Ed Tanous4a0cb852018-10-15 07:55:04 -07001864 const std::string &parent_iface_id = params[0];
1865 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001866 res.jsonValue["@odata.type"] =
1867 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1868 res.jsonValue["@odata.context"] =
1869 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1870 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001871
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001872 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 {
1874 return;
1875 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001876
Ed Tanous1abe55e2018-09-05 08:30:59 -07001877 // Get single eth interface data, and call the below callback for JSON
1878 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001879 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001880 params[1],
1881 [this, asyncResp, parent_iface_id{std::string(params[0])},
1882 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001883 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001884 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1885 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1886 const boost::container::flat_set<IPv6AddressData>
1887 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001888 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001889 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001890 parseInterfaceData(asyncResp->res.jsonValue,
1891 parent_iface_id, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001892 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001893 }
1894 else
1895 {
1896 // ... otherwise return error
1897 // TODO(Pawel)consider distinguish between non existing
1898 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001899 messages::resourceNotFound(
1900 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001901 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001902 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001903 }
1904
Ed Tanous1abe55e2018-09-05 08:30:59 -07001905 void doPatch(crow::Response &res, const crow::Request &req,
1906 const std::vector<std::string> &params) override
1907 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001908 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001909 if (params.size() != 2)
1910 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001911 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001912 return;
1913 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001914
Ed Tanous1abe55e2018-09-05 08:30:59 -07001915 const std::string &parentIfaceId = params[0];
1916 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001917
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001918 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001919 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001920 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1921 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 return;
1923 }
1924
Ed Tanous0627a2c2018-11-29 17:09:23 -08001925 bool vlanEnable = false;
1926 uint64_t vlanId = 0;
1927
1928 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1929 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001930 {
1931 return;
1932 }
1933
1934 // Get single eth interface data, and call the below callback for JSON
1935 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001936 getEthernetIfaceData(
1937 params[1],
1938 [this, asyncResp, parentIfaceId{std::string(params[0])},
1939 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1940 const bool &success, const EthernetInterfaceData &ethData,
1941 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1942 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1943 const boost::container::flat_set<IPv6AddressData>
1944 &ipv6StaticData) {
1945 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001946 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001947 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1948 ifaceId, ethData, ipv4Data, ipv6Data,
1949 ipv6StaticData);
1950 auto callback =
1951 [asyncResp](const boost::system::error_code ec) {
1952 if (ec)
1953 {
1954 messages::internalError(asyncResp->res);
1955 }
1956 };
1957
1958 if (vlanEnable == true)
1959 {
1960 crow::connections::systemBus->async_method_call(
1961 std::move(callback), "xyz.openbmc_project.Network",
1962 "/xyz/openbmc_project/network/" + ifaceId,
1963 "org.freedesktop.DBus.Properties", "Set",
1964 "xyz.openbmc_project.Network.VLAN", "Id",
1965 std::variant<uint32_t>(vlanId));
1966 }
1967 else
1968 {
1969 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1970 "vlan interface";
1971 crow::connections::systemBus->async_method_call(
1972 std::move(callback), "xyz.openbmc_project.Network",
1973 std::string("/xyz/openbmc_project/network/") +
1974 ifaceId,
1975 "xyz.openbmc_project.Object.Delete", "Delete");
1976 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001977 }
1978 else
1979 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001980 // TODO(Pawel)consider distinguish between non existing
1981 // object, and other errors
1982 messages::resourceNotFound(
1983 asyncResp->res, "VLAN Network Interface", ifaceId);
1984 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001985 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001986 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001987 }
1988
1989 void doDelete(crow::Response &res, const crow::Request &req,
1990 const std::vector<std::string> &params) override
1991 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001992 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001993 if (params.size() != 2)
1994 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001995 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001996 return;
1997 }
1998
1999 const std::string &parentIfaceId = params[0];
2000 const std::string &ifaceId = params[1];
2001
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002002 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002003 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002004 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2005 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002006 return;
2007 }
2008
2009 // Get single eth interface data, and call the below callback for JSON
2010 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002011 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002012 params[1],
2013 [this, asyncResp, parentIfaceId{std::string(params[0])},
2014 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002015 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002016 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2017 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2018 const boost::container::flat_set<IPv6AddressData>
2019 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002020 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002021 {
Ed Tanous0f74e642018-11-12 15:17:05 -08002022 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002023 ifaceId, ethData, ipv4Data, ipv6Data,
2024 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002025
Jason M. Billsf12894f2018-10-09 12:45:45 -07002026 auto callback =
2027 [asyncResp](const boost::system::error_code ec) {
2028 if (ec)
2029 {
2030 messages::internalError(asyncResp->res);
2031 }
2032 };
2033 crow::connections::systemBus->async_method_call(
2034 std::move(callback), "xyz.openbmc_project.Network",
2035 std::string("/xyz/openbmc_project/network/") + ifaceId,
2036 "xyz.openbmc_project.Object.Delete", "Delete");
2037 }
2038 else
2039 {
2040 // ... otherwise return error
2041 // TODO(Pawel)consider distinguish between non existing
2042 // object, and other errors
2043 messages::resourceNotFound(
2044 asyncResp->res, "VLAN Network Interface", ifaceId);
2045 }
2046 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002047 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002048};
2049
2050/**
2051 * VlanNetworkInterfaceCollection derived class for delivering
2052 * VLANNetworkInterface Collection Schema
2053 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002054class VlanNetworkInterfaceCollection : public Node
2055{
2056 public:
2057 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002058 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002059 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2060 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002061 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002062 entityPrivileges = {
2063 {boost::beast::http::verb::get, {{"Login"}}},
2064 {boost::beast::http::verb::head, {{"Login"}}},
2065 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2066 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2067 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2068 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002069 }
2070
Ed Tanous1abe55e2018-09-05 08:30:59 -07002071 private:
2072 /**
2073 * Functions triggers appropriate requests on DBus
2074 */
2075 void doGet(crow::Response &res, const crow::Request &req,
2076 const std::vector<std::string> &params) override
2077 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002078 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002079 if (params.size() != 1)
2080 {
2081 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002082 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002083 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002084 }
2085
Ed Tanous4a0cb852018-10-15 07:55:04 -07002086 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002087
Ed Tanous4a0cb852018-10-15 07:55:04 -07002088 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002089 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002090 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002091 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002092 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002093 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002094 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002095 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002096 messages::internalError(asyncResp->res);
2097 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002098 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002099
2100 if (iface_list.find(rootInterfaceName) == iface_list.end())
2101 {
2102 messages::resourceNotFound(asyncResp->res,
2103 "VLanNetworkInterfaceCollection",
2104 rootInterfaceName);
2105 return;
2106 }
2107
Ed Tanous0f74e642018-11-12 15:17:05 -08002108 asyncResp->res.jsonValue["@odata.type"] =
2109 "#VLanNetworkInterfaceCollection."
2110 "VLanNetworkInterfaceCollection";
2111 asyncResp->res.jsonValue["@odata.context"] =
2112 "/redfish/v1/$metadata"
2113 "#VLanNetworkInterfaceCollection."
2114 "VLanNetworkInterfaceCollection";
2115 asyncResp->res.jsonValue["Name"] =
2116 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002117
Jason M. Billsf12894f2018-10-09 12:45:45 -07002118 nlohmann::json iface_array = nlohmann::json::array();
2119
2120 for (const std::string &iface_item : iface_list)
2121 {
2122 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2123 {
2124 iface_array.push_back(
2125 {{"@odata.id",
2126 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2127 rootInterfaceName + "/VLANs/" + iface_item}});
2128 }
2129 }
2130
Jason M. Billsf12894f2018-10-09 12:45:45 -07002131 asyncResp->res.jsonValue["Members@odata.count"] =
2132 iface_array.size();
2133 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2134 asyncResp->res.jsonValue["@odata.id"] =
2135 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2136 rootInterfaceName + "/VLANs";
2137 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002138 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002139
Ed Tanous1abe55e2018-09-05 08:30:59 -07002140 void doPost(crow::Response &res, const crow::Request &req,
2141 const std::vector<std::string> &params) override
2142 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002143 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002144 if (params.size() != 1)
2145 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002146 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002147 return;
2148 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002149 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002150 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002151 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2152 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002153 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002154 return;
2155 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002156 // Need both vlanId and vlanEnable to service this request
2157 if (!vlanId)
2158 {
2159 messages::propertyMissing(asyncResp->res, "VLANId");
2160 }
2161 if (!vlanEnable)
2162 {
2163 messages::propertyMissing(asyncResp->res, "VLANEnable");
2164 }
2165 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2166 {
2167 return;
2168 }
2169
Ed Tanous4a0cb852018-10-15 07:55:04 -07002170 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002171 auto callback = [asyncResp](const boost::system::error_code ec) {
2172 if (ec)
2173 {
2174 // TODO(ed) make more consistent error messages based on
2175 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002176 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002177 return;
2178 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002179 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002180 };
2181 crow::connections::systemBus->async_method_call(
2182 std::move(callback), "xyz.openbmc_project.Network",
2183 "/xyz/openbmc_project/network",
2184 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002185 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002186 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002187};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002188} // namespace redfish