blob: c4f60a9c96f4961af319b411f0afffe2d926d944 [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{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700591 auto callback =
592 [asyncResp, ipIdx, name{std::string(name)},
593 newValue{std::move(newValue)}](const boost::system::error_code ec) {
594 if (ec)
595 {
596 messages::internalError(asyncResp->res);
597 }
598 };
Ed Tanousb01bf292019-03-25 19:25:26 +0000599
600 crow::connections::systemBus->async_method_call(
601 std::move(callback), "xyz.openbmc_project.Network",
602 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
603 "org.freedesktop.DBus.Properties", "Set",
604 "xyz.openbmc_project.Network.IP", name,
605 std::variant<std::string>(newValue));
606}
607
608/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700609 * @brief Modifies SubnetMask for given IP
610 *
611 * @param[in] ifaceId Id of interface whose IP should be modified
612 * @param[in] ipIdx Index of IP in input array that should be
613 * modified
614 * @param[in] ipHash DBus Hash id of modified IP
Ed Tanous4a0cb852018-10-15 07:55:04 -0700615 * @param[in] newValue Mask as PrefixLength in bitcount
616 * @param[io] asyncResp Response object that will be returned to client
617 *
618 * @return None
619 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000620inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700621 const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700622 uint8_t &newValue,
623 std::shared_ptr<AsyncResp> asyncResp)
624{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700625 auto callback = [asyncResp, ipIdx](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700626 if (ec)
627 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800628 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700629 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700630 };
631
632 crow::connections::systemBus->async_method_call(
633 std::move(callback), "xyz.openbmc_project.Network",
634 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
635 "org.freedesktop.DBus.Properties", "Set",
636 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800637 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700638}
639
640/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700641 * @brief Deletes given IPv4
642 *
643 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700644 * @param[in] ipHash DBus Hash id of IP that should be deleted
645 * @param[io] asyncResp Response object that will be returned to client
646 *
647 * @return None
648 */
649inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700650 const std::shared_ptr<AsyncResp> asyncResp)
651{
652 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700653 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 if (ec)
655 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800656 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100657 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700658 },
659 "xyz.openbmc_project.Network",
660 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
661 "xyz.openbmc_project.Object.Delete", "Delete");
662}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663
Ed Tanous4a0cb852018-10-15 07:55:04 -0700664/**
665 * @brief Creates IPv4 with given data
666 *
667 * @param[in] ifaceId Id of interface whose IP should be deleted
668 * @param[in] ipIdx Index of IP in input array that should be deleted
669 * @param[in] ipHash DBus Hash id of IP that should be deleted
670 * @param[io] asyncResp Response object that will be returned to client
671 *
672 * @return None
673 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000674inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
675 uint8_t subnetMask, const std::string &gateway,
676 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700677 std::shared_ptr<AsyncResp> asyncResp)
678{
Ed Tanous43b761d2019-02-13 20:10:56 -0800679 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700680 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800682 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 };
685
Ed Tanous4a0cb852018-10-15 07:55:04 -0700686 crow::connections::systemBus->async_method_call(
687 std::move(createIpHandler), "xyz.openbmc_project.Network",
688 "/xyz/openbmc_project/network/" + ifaceId,
689 "xyz.openbmc_project.Network.IP.Create", "IP",
690 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
691 gateway);
692}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500693
694/**
695 * @brief Deletes given IPv6
696 *
697 * @param[in] ifaceId Id of interface whose IP should be deleted
698 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500699 * @param[io] asyncResp Response object that will be returned to client
700 *
701 * @return None
702 */
703inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500704 const std::shared_ptr<AsyncResp> asyncResp)
705{
706 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700707 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500708 if (ec)
709 {
710 messages::internalError(asyncResp->res);
711 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500712 },
713 "xyz.openbmc_project.Network",
714 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
715 "xyz.openbmc_project.Object.Delete", "Delete");
716}
717
718/**
719 * @brief Creates IPv6 with given data
720 *
721 * @param[in] ifaceId Id of interface whose IP should be added
722 * @param[in] ipIdx Index of IP in input array that should be added
723 * @param[in] prefixLength Prefix length that needs to be added
724 * @param[in] address IP address that needs to be added
725 * @param[io] asyncResp Response object that will be returned to client
726 *
727 * @return None
728 */
729inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
730 uint8_t prefixLength, const std::string &address,
731 std::shared_ptr<AsyncResp> asyncResp)
732{
733 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
734 if (ec)
735 {
736 messages::internalError(asyncResp->res);
737 }
738 };
739 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
740 // does not have assosiated gateway property
741 crow::connections::systemBus->async_method_call(
742 std::move(createIpHandler), "xyz.openbmc_project.Network",
743 "/xyz/openbmc_project/network/" + ifaceId,
744 "xyz.openbmc_project.Network.IP.Create", "IP",
745 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
746 "");
747}
748
manojkiraneda2a133282019-02-19 13:09:43 +0530749using GetAllPropertiesType =
750 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
751
752inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
753{
754 auto getConfig = [asyncResp](const boost::system::error_code error_code,
755 const GetAllPropertiesType &dbus_data) {
756 if (error_code)
757 {
758 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
759 messages::internalError(asyncResp->res);
760 return;
761 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500762 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530763 for (const auto &property : dbus_data)
764 {
765 auto value =
766 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
767
768 if (value == nullptr)
769 {
770 continue;
771 }
772 if (property.first == "DNSEnabled")
773 {
774 DHCPConfigTypeJson["UseDNSServers"] = *value;
775 }
776 else if (property.first == "HostNameEnabled")
777 {
778 DHCPConfigTypeJson["UseDomainName"] = *value;
779 }
780 else if (property.first == "NTPEnabled")
781 {
782 DHCPConfigTypeJson["UseNTPServers"] = *value;
783 }
784 }
785 };
786 crow::connections::systemBus->async_method_call(
787 std::move(getConfig), "xyz.openbmc_project.Network",
788 "/xyz/openbmc_project/network/config/dhcp",
789 "org.freedesktop.DBus.Properties", "GetAll",
790 "xyz.openbmc_project.Network.DHCPConfiguration");
791}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792
Ed Tanous4a0cb852018-10-15 07:55:04 -0700793/**
794 * Function that retrieves all properties for given Ethernet Interface
795 * Object
796 * from EntityManager Network Manager
797 * @param ethiface_id a eth interface id to query on DBus
798 * @param callback a function that shall be called to convert Dbus output
799 * into JSON
800 */
801template <typename CallbackFunc>
802void getEthernetIfaceData(const std::string &ethiface_id,
803 CallbackFunc &&callback)
804{
805 crow::connections::systemBus->async_method_call(
806 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
807 const boost::system::error_code error_code,
808 const GetManagedObjects &resp) {
809 EthernetInterfaceData ethData{};
810 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500811 boost::container::flat_set<IPv6AddressData> ipv6Data;
812 boost::container::flat_set<IPv6AddressData> ipv6StaticData;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700813
814 if (error_code)
815 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500816 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700817 return;
818 }
819
Ed Tanous4c9afe42019-05-03 16:59:57 -0700820 bool found =
821 extractEthernetInterfaceData(ethiface_id, resp, ethData);
822 if (!found)
823 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500824 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700825 return;
826 }
827
Ed Tanous4a0cb852018-10-15 07:55:04 -0700828 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700829 // Fix global GW
830 for (IPv4AddressData &ipv4 : ipv4Data)
831 {
832 if ((ipv4.linktype == LinkType::Global) &&
833 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700835 ipv4.gateway = ethData.default_gateway;
836 }
837 }
838
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500839 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700840 // Finally make a callback with usefull data
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500841 callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700842 },
843 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
844 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
845};
846
847/**
848 * Function that retrieves all Ethernet Interfaces available through Network
849 * Manager
850 * @param callback a function that shall be called to convert Dbus output
851 * into JSON.
852 */
853template <typename CallbackFunc>
854void getEthernetIfaceList(CallbackFunc &&callback)
855{
856 crow::connections::systemBus->async_method_call(
857 [callback{std::move(callback)}](
858 const boost::system::error_code error_code,
859 GetManagedObjects &resp) {
860 // Callback requires vector<string> to retrieve all available
861 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700862 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700863 iface_list.reserve(resp.size());
864 if (error_code)
865 {
866 callback(false, iface_list);
867 return;
868 }
869
870 // Iterate over all retrieved ObjectPaths.
871 for (const auto &objpath : resp)
872 {
873 // And all interfaces available for certain ObjectPath.
874 for (const auto &interface : objpath.second)
875 {
876 // If interface is
877 // xyz.openbmc_project.Network.EthernetInterface, this is
878 // what we're looking for.
879 if (interface.first ==
880 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700882 // Cut out everyting until last "/", ...
883 const std::string &iface_id = objpath.first.str;
884 std::size_t last_pos = iface_id.rfind("/");
885 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700887 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700888 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 }
890 }
891 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700892 }
893 // Finally make a callback with useful data
894 callback(true, iface_list);
895 },
896 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
897 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100898};
899
900/**
901 * EthernetCollection derived class for delivering Ethernet Collection Schema
902 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903class EthernetCollection : public Node
904{
905 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700906 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700908 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 entityPrivileges = {
911 {boost::beast::http::verb::get, {{"Login"}}},
912 {boost::beast::http::verb::head, {{"Login"}}},
913 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
914 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
915 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
916 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
917 }
918
919 private:
920 /**
921 * Functions triggers appropriate requests on DBus
922 */
923 void doGet(crow::Response &res, const crow::Request &req,
924 const std::vector<std::string> &params) override
925 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800926 res.jsonValue["@odata.type"] =
927 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
928 res.jsonValue["@odata.context"] =
929 "/redfish/v1/"
930 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
931 res.jsonValue["@odata.id"] =
932 "/redfish/v1/Managers/bmc/EthernetInterfaces";
933 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
934 res.jsonValue["Description"] =
935 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700936 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700937 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700938 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700939 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700940 [asyncResp](
941 const bool &success,
942 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700943 if (!success)
944 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700945 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700946 return;
947 }
948
Ed Tanous4c9afe42019-05-03 16:59:57 -0700949 nlohmann::json &iface_array =
950 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700951 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500952 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700953 for (const std::string &iface_item : iface_list)
954 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500955 std::size_t found = iface_item.find(tag);
956 if (found == std::string::npos)
957 {
958 iface_array.push_back(
959 {{"@odata.id",
960 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
961 iface_item}});
962 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700963 }
964
Ed Tanous4c9afe42019-05-03 16:59:57 -0700965 asyncResp->res.jsonValue["Members@odata.count"] =
966 iface_array.size();
967 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700968 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700969 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700970 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100971};
972
973/**
974 * EthernetInterface derived class for delivering Ethernet Schema
975 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700976class EthernetInterface : public Node
977{
978 public:
979 /*
980 * Default Constructor
981 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700982 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700983 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700984 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700985 std::string())
986 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987 entityPrivileges = {
988 {boost::beast::http::verb::get, {{"Login"}}},
989 {boost::beast::http::verb::head, {{"Login"}}},
990 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
991 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
992 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
993 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200994 }
995
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800997 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700998 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001000 asyncResp->res.jsonValue["HostName"] = hostname;
1001 crow::connections::systemBus->async_method_call(
1002 [asyncResp](const boost::system::error_code ec) {
1003 if (ec)
1004 {
1005 messages::internalError(asyncResp->res);
1006 }
1007 },
1008 "xyz.openbmc_project.Network",
1009 "/xyz/openbmc_project/network/config",
1010 "org.freedesktop.DBus.Properties", "Set",
1011 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001012 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001013 }
1014
Ratan Guptad5776652019-03-03 08:47:22 +05301015 void handleMACAddressPatch(const std::string &ifaceId,
1016 const std::string &macAddress,
1017 const std::shared_ptr<AsyncResp> &asyncResp)
1018 {
1019 crow::connections::systemBus->async_method_call(
1020 [asyncResp, macAddress](const boost::system::error_code ec) {
1021 if (ec)
1022 {
1023 messages::internalError(asyncResp->res);
1024 return;
1025 }
Ratan Guptad5776652019-03-03 08:47:22 +05301026 },
1027 "xyz.openbmc_project.Network",
1028 "/xyz/openbmc_project/network/" + ifaceId,
1029 "org.freedesktop.DBus.Properties", "Set",
1030 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1031 std::variant<std::string>(macAddress));
1032 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001033
Jennifer Leeda131a92019-04-24 15:13:55 -07001034 void setDHCPEnabled(const std::string &ifaceId,
1035 const std::string &propertyName, const bool &value,
1036 const std::shared_ptr<AsyncResp> asyncResp)
1037 {
1038 crow::connections::systemBus->async_method_call(
1039 [asyncResp](const boost::system::error_code ec) {
1040 if (ec)
1041 {
1042 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1043 messages::internalError(asyncResp->res);
1044 return;
1045 }
1046 },
1047 "xyz.openbmc_project.Network",
1048 "/xyz/openbmc_project/network/" + ifaceId,
1049 "org.freedesktop.DBus.Properties", "Set",
1050 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1051 std::variant<bool>{value});
1052 }
1053 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1054 const std::shared_ptr<AsyncResp> asyncResp)
1055 {
1056 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1057 crow::connections::systemBus->async_method_call(
1058 [asyncResp](const boost::system::error_code ec) {
1059 if (ec)
1060 {
1061 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1062 messages::internalError(asyncResp->res);
1063 return;
1064 }
1065 },
1066 "xyz.openbmc_project.Network",
1067 "/xyz/openbmc_project/network/config/dhcp",
1068 "org.freedesktop.DBus.Properties", "Set",
1069 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1070 std::variant<bool>{value});
1071 }
Ratan Guptad5776652019-03-03 08:47:22 +05301072
Jennifer Leeda131a92019-04-24 15:13:55 -07001073 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1074 const std::shared_ptr<AsyncResp> asyncResp)
1075 {
1076 std::optional<bool> dhcpEnabled;
1077 std::optional<bool> useDNSServers;
1078 std::optional<bool> useDomainName;
1079 std::optional<bool> useNTPServers;
1080
1081 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1082 dhcpEnabled, "UseDNSServers", useDNSServers,
1083 "UseDomainName", useDomainName,
1084 "UseNTPServers", useNTPServers))
1085 {
1086 return;
1087 }
1088
1089 if (dhcpEnabled)
1090 {
1091 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1092 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1093 }
1094
1095 if (useDNSServers)
1096 {
1097 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1098 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1099 }
1100
1101 if (useDomainName)
1102 {
1103 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1104 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1105 }
1106
1107 if (useNTPServers)
1108 {
1109 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1110 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1111 }
1112 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001113 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301114 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001115 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1116 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001117 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301118 if (!input.is_array())
1119 {
1120 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1121 "IPv4Addresses");
1122 return;
1123 }
1124
Ed Tanous4a0cb852018-10-15 07:55:04 -07001125 int entryIdx = 0;
1126 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1127 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001128 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001129 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001130 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001131 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132
Ratan Guptaf476acb2019-03-02 16:46:57 +05301133 if (thisJson.is_null())
1134 {
1135 if (thisData != ipv4Data.end())
1136 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001137 deleteIPv4(ifaceId, thisData->id, asyncResp);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301138 thisData++;
1139 }
1140 else
1141 {
1142 messages::propertyValueFormatError(
1143 asyncResp->res, input.dump(), pathString);
1144 return;
1145 // TODO(ratagupt) Not sure about the property where value is
1146 // list and if unable to update one of the
1147 // list value then should we proceed further or
1148 // break there, would ask in the redfish forum
1149 // till then we stop processing the next list item.
1150 }
1151 entryIdx++;
1152 continue; // not an error as per the redfish spec.
1153 }
1154
Ratan Gupta9474b372019-03-01 15:13:37 +05301155 if (thisJson.empty())
1156 {
1157 if (thisData != ipv4Data.end())
1158 {
1159 thisData++;
1160 }
1161 else
1162 {
1163 messages::propertyMissing(asyncResp->res,
1164 pathString + "/Address");
1165 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301166 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301167 // list and if unable to update one of the
1168 // list value then should we proceed further or
1169 // break there, would ask in the redfish forum
1170 // till then we stop processing the next list item.
1171 }
1172 entryIdx++;
1173 continue; // not an error as per the redfish spec.
1174 }
1175
Ed Tanous537174c2018-12-10 15:09:31 -08001176 std::optional<std::string> address;
Ed Tanous537174c2018-12-10 15:09:31 -08001177 std::optional<std::string> subnetMask;
1178 std::optional<std::string> gateway;
1179
1180 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
Johnathan Mantey7e27d832019-06-11 10:31:56 -07001181 address, "SubnetMask", subnetMask,
1182 "Gateway", gateway))
Ed Tanous537174c2018-12-10 15:09:31 -08001183 {
1184 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001185 }
1186
Ed Tanous537174c2018-12-10 15:09:31 -08001187 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001188 {
Ed Tanous537174c2018-12-10 15:09:31 -08001189 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 {
Ed Tanous537174c2018-12-10 15:09:31 -08001191 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001192 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001193 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001194 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001195 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001196
Ed Tanous537174c2018-12-10 15:09:31 -08001197 uint8_t prefixLength = 0;
1198 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001199 {
Ed Tanous537174c2018-12-10 15:09:31 -08001200 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001201 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001202 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001203 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001204 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001205 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001206 }
1207 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001208
Ed Tanous537174c2018-12-10 15:09:31 -08001209 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001210 {
Ed Tanous537174c2018-12-10 15:09:31 -08001211 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001212 {
Ed Tanous537174c2018-12-10 15:09:31 -08001213 messages::propertyValueFormatError(asyncResp->res, *gateway,
1214 pathString + "/Gateway");
1215 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001216 }
1217 }
1218
Ratan Guptaf476acb2019-03-02 16:46:57 +05301219 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001220 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001221 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301222 // Apply changes
1223 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001224 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001225 auto callback =
1226 [asyncResp](const boost::system::error_code ec) {
1227 if (ec)
1228 {
1229 messages::internalError(asyncResp->res);
1230 return;
1231 }
1232 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301233
Ed Tanous4a0cb852018-10-15 07:55:04 -07001234 crow::connections::systemBus->async_method_call(
1235 std::move(callback), "xyz.openbmc_project.Network",
1236 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1237 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301238 "org.freedesktop.DBus.Properties", "Set",
1239 "xyz.openbmc_project.Network.IP", "Address",
1240 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001241 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301242
1243 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001244 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301245 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
Johnathan Mantey286b9112019-06-10 13:38:04 -07001246 thisData->id, prefixLength,
1247 asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301249
Ratan Guptaf476acb2019-03-02 16:46:57 +05301250 if (gateway)
1251 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001252 auto callback =
1253 [asyncResp](const boost::system::error_code ec) {
1254 if (ec)
1255 {
1256 messages::internalError(asyncResp->res);
1257 return;
1258 }
1259 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301260
1261 crow::connections::systemBus->async_method_call(
1262 std::move(callback), "xyz.openbmc_project.Network",
1263 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1264 thisData->id,
1265 "org.freedesktop.DBus.Properties", "Set",
1266 "xyz.openbmc_project.Network.IP", "Gateway",
1267 std::variant<std::string>(*gateway));
1268 }
1269
Ed Tanous4a0cb852018-10-15 07:55:04 -07001270 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001272 else
1273 {
1274 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001275 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001276 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001277 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001278 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001279 continue;
1280 }
1281
Ed Tanous537174c2018-12-10 15:09:31 -08001282 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001283 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001284 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001285 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001286 continue;
1287 }
1288
Ed Tanous537174c2018-12-10 15:09:31 -08001289 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001290 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001291 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001292 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001293 continue;
1294 }
1295
Ed Tanousb01bf292019-03-25 19:25:26 +00001296 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1297 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301298
1299 nlohmann::json &ipv4AddressJson =
1300 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1301 ipv4AddressJson["Address"] = *address;
1302 ipv4AddressJson["SubnetMask"] = *subnetMask;
1303 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001304 }
1305 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001306 }
1307 }
1308
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001309 void handleStaticNameServersPatch(
1310 const std::string &ifaceId,
1311 const std::vector<std::string> &updatedStaticNameServers,
1312 const std::shared_ptr<AsyncResp> &asyncResp)
1313 {
1314 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001315 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001316 if (ec)
1317 {
1318 messages::internalError(asyncResp->res);
1319 return;
1320 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001321 },
1322 "xyz.openbmc_project.Network",
1323 "/xyz/openbmc_project/network/" + ifaceId,
1324 "org.freedesktop.DBus.Properties", "Set",
1325 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1326 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1327 }
1328
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001329 void handleIPv6StaticAddressesPatch(
1330 const std::string &ifaceId, nlohmann::json &input,
1331 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1332 const std::shared_ptr<AsyncResp> asyncResp)
1333 {
1334 if (!input.is_array())
1335 {
1336 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1337 "IPv6StaticAddresses");
1338 return;
1339 }
1340
1341 int entryIdx = 0;
1342 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1343 ipv6StaticData.begin();
1344 for (nlohmann::json &thisJson : input)
1345 {
1346 std::string pathString =
1347 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1348
1349 if (thisJson.is_null())
1350 {
1351 if (thisData != ipv6StaticData.end())
1352 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001353 deleteIPv6(ifaceId, thisData->id, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001354 thisData++;
1355 }
1356 else
1357 {
1358 messages::propertyValueFormatError(
1359 asyncResp->res, input.dump(), pathString);
1360 return;
1361 }
1362 entryIdx++;
1363 continue;
1364 }
1365
1366 if (thisJson.empty())
1367 {
1368 if (thisData != ipv6StaticData.end())
1369 {
1370 thisData++;
1371 }
1372 else
1373 {
1374 messages::propertyMissing(asyncResp->res,
1375 pathString + "/Address");
1376 return;
1377 }
1378 entryIdx++;
1379 continue;
1380 }
1381
1382 std::optional<std::string> address;
1383 std::optional<uint8_t> prefixLength;
1384
1385 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1386 address, "PrefixLength", prefixLength))
1387 {
1388 return;
1389 }
1390
1391 // if IP address exist then modify it.
1392 if (thisData != ipv6StaticData.end())
1393 {
1394 // Apply changes
1395 if (address)
1396 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001397 auto callback =
1398 [asyncResp](const boost::system::error_code ec) {
1399 if (ec)
1400 {
1401 messages::internalError(asyncResp->res);
1402 return;
1403 }
1404 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001405
1406 crow::connections::systemBus->async_method_call(
1407 std::move(callback), "xyz.openbmc_project.Network",
1408 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1409 thisData->id,
1410 "org.freedesktop.DBus.Properties", "Set",
1411 "xyz.openbmc_project.Network.IP", "Address",
1412 std::variant<std::string>(*address));
1413 }
1414
1415 if (prefixLength)
1416 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001417 auto callback =
1418 [asyncResp](const boost::system::error_code ec) {
1419 if (ec)
1420 {
1421 messages::internalError(asyncResp->res);
1422 return;
1423 }
1424 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001425
1426 crow::connections::systemBus->async_method_call(
1427 std::move(callback), "xyz.openbmc_project.Network",
1428 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1429 thisData->id,
1430 "org.freedesktop.DBus.Properties", "Set",
1431 "xyz.openbmc_project.Network.IP", "PrefixLength",
1432 std::variant<uint8_t>(*prefixLength));
1433 }
1434
1435 thisData++;
1436 }
1437 else
1438 {
1439 // Create IPv6 with provided data
1440
1441 if (!prefixLength)
1442 {
1443 messages::propertyMissing(asyncResp->res,
1444 pathString + "/PrefixLength");
1445 continue;
1446 }
1447
1448 if (!address)
1449 {
1450 messages::propertyMissing(asyncResp->res,
1451 pathString + "/Address");
1452 continue;
1453 }
1454
1455 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1456 asyncResp);
1457
1458 nlohmann::json &ipv6StaticAddressJson =
1459 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1460 ipv6StaticAddressJson["Address"] = *address;
1461 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1462 }
1463 entryIdx++;
1464 }
1465 }
1466
Ed Tanous0f74e642018-11-12 15:17:05 -08001467 void parseInterfaceData(
1468 nlohmann::json &json_response, const std::string &iface_id,
1469 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001470 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1471 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1472 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001473 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001474 json_response["Id"] = iface_id;
1475 json_response["@odata.id"] =
1476 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001477 json_response["InterfaceEnabled"] = true;
1478 if (ethData.speed == 0)
1479 {
1480 json_response["LinkStatus"] = "NoLink";
1481 json_response["Status"] = {
1482 {"Health", "OK"},
1483 {"State", "Disabled"},
1484 };
1485 }
1486 else
1487 {
1488 json_response["LinkStatus"] = "LinkUp";
1489 json_response["Status"] = {
1490 {"Health", "OK"},
1491 {"State", "Enabled"},
1492 };
1493 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001494 json_response["SpeedMbps"] = ethData.speed;
1495 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001496 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301497
Ed Tanous4a0cb852018-10-15 07:55:04 -07001498 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001500 json_response["HostName"] = ethData.hostname;
1501 }
1502
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001503 json_response["VLANs"] = {
1504 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1505 iface_id + "/VLANs"}};
1506
Ed Tanous029573d2019-02-01 10:57:49 -08001507 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001508 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509
Ed Tanous4a0cb852018-10-15 07:55:04 -07001510 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001511 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001512 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1513 ipv4_array = nlohmann::json::array();
1514 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001515 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001516
1517 std::string gatewayStr = ipv4_config.gateway;
1518 if (gatewayStr.empty())
1519 {
1520 gatewayStr = "0.0.0.0";
1521 }
1522
Ed Tanous029573d2019-02-01 10:57:49 -08001523 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1524 {"SubnetMask", ipv4_config.netmask},
1525 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001526 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001529 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001530
1531 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1532 ipv6_array = nlohmann::json::array();
1533 for (auto &ipv6_config : ipv6Data)
1534 {
1535 ipv6_array.push_back({{"Address", ipv6_config.address},
1536 {"PrefixLength", ipv6_config.prefixLength},
1537 {"AddressOrigin", ipv6_config.origin}});
1538 }
1539
1540 nlohmann::json &ipv6_static_array =
1541 json_response["IPv6StaticAddresses"];
1542 ipv6_static_array = nlohmann::json::array();
1543 for (auto &ipv6_static_config : ipv6StaticData)
1544 {
1545 ipv6_static_array.push_back(
1546 {{"Address", ipv6_static_config.address},
1547 {"PrefixLength", ipv6_static_config.prefixLength}});
1548 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 }
1550
1551 /**
1552 * Functions triggers appropriate requests on DBus
1553 */
1554 void doGet(crow::Response &res, const crow::Request &req,
1555 const std::vector<std::string> &params) override
1556 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001557 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001558 if (params.size() != 1)
1559 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001560 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 return;
1562 }
1563
Ed Tanous4a0cb852018-10-15 07:55:04 -07001564 getEthernetIfaceData(
1565 params[0],
1566 [this, asyncResp, iface_id{std::string(params[0])}](
1567 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001568 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1569 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1570 const boost::container::flat_set<IPv6AddressData>
1571 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001572 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 // TODO(Pawel)consider distinguish between non existing
1575 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001576 messages::resourceNotFound(asyncResp->res,
1577 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001578 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001580
1581 // because this has no dependence on the interface at this
1582 // point, it needs to be done after we know the interface
1583 // exists, not before.
1584 getDHCPConfigData(asyncResp);
1585
Ed Tanous0f74e642018-11-12 15:17:05 -08001586 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001587 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001588 asyncResp->res.jsonValue["@odata.context"] =
1589 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1590 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1591 asyncResp->res.jsonValue["Description"] =
1592 "Management Network Interface";
1593
1594 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001595 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001596 });
1597 }
1598
1599 void doPatch(crow::Response &res, const crow::Request &req,
1600 const std::vector<std::string> &params) override
1601 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001602 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001603 if (params.size() != 1)
1604 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001605 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001606 return;
1607 }
1608
Ed Tanous4a0cb852018-10-15 07:55:04 -07001609 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001611 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301612 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001613 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301614 std::optional<nlohmann::json> ipv4Addresses;
1615 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001616 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001617 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001618 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001619 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001620
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001621 if (!json_util::readJson(
1622 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Johnathan Mantey6ca6ac12019-06-10 12:21:31 -07001623 "MACAddress", macAddress, "StaticNameServers",
1624 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
1625 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
1626 nameServers, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 {
1628 return;
1629 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301630
Jennifer Leeda131a92019-04-24 15:13:55 -07001631 if (dhcpv4)
1632 {
1633 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1634 }
1635
Ed Tanous4a0cb852018-10-15 07:55:04 -07001636 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001638 getEthernetIfaceData(
1639 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001640 [this, asyncResp, iface_id, hostname = std::move(hostname),
1641 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001642 ipv4Addresses = std::move(ipv4Addresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001643 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001644 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001645 staticNameServers = std::move(staticNameServers),
1646 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001647 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001648 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1649 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1650 const boost::container::flat_set<IPv6AddressData>
1651 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001652 if (!success)
1653 {
1654 // ... otherwise return error
1655 // TODO(Pawel)consider distinguish between non existing
1656 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001657 messages::resourceNotFound(asyncResp->res,
1658 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659 return;
1660 }
1661
Ed Tanous0627a2c2018-11-29 17:09:23 -08001662 if (hostname)
1663 {
1664 handleHostnamePatch(*hostname, asyncResp);
1665 }
1666
Ratan Guptad5776652019-03-03 08:47:22 +05301667 if (macAddress)
1668 {
1669 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1670 }
1671
Ed Tanous0627a2c2018-11-29 17:09:23 -08001672 if (ipv4Addresses)
1673 {
Ed Tanous537174c2018-12-10 15:09:31 -08001674 // TODO(ed) for some reason the capture of ipv4Addresses
1675 // above is returning a const value, not a non-const value.
1676 // This doesn't really work for us, as we need to be able to
1677 // efficiently move out the intermedia nlohmann::json
1678 // objects. This makes a copy of the structure, and operates
1679 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301680 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001681 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001682 }
1683
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001684 if (nameServers)
1685 {
1686 // Data.Permissions is read-only
1687 messages::propertyNotWritable(asyncResp->res,
1688 "NameServers");
1689 }
1690
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001691 if (staticNameServers)
1692 {
1693 handleStaticNameServersPatch(iface_id, *staticNameServers,
1694 asyncResp);
1695 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001696
1697 if (ipv6DefaultGateway)
1698 {
1699 messages::propertyNotWritable(asyncResp->res,
1700 "IPv6DefaultGateway");
1701 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001702
1703 if (ipv6StaticAddresses)
1704 {
1705 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1706 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1707 ipv6StaticData, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001708 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 });
1710 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001711};
1712
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001713/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001714 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1715 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001716 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717class VlanNetworkInterface : public Node
1718{
1719 public:
1720 /*
1721 * Default Constructor
1722 */
1723 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001724 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001725 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001726 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001727 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001729 entityPrivileges = {
1730 {boost::beast::http::verb::get, {{"Login"}}},
1731 {boost::beast::http::verb::head, {{"Login"}}},
1732 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1733 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1734 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1735 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001736 }
1737
Ed Tanous1abe55e2018-09-05 08:30:59 -07001738 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001739 void parseInterfaceData(
1740 nlohmann::json &json_response, const std::string &parent_iface_id,
1741 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001742 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1743 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1744 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001746 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001747 json_response["Id"] = iface_id;
1748 json_response["@odata.id"] =
1749 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1750 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001751
Ed Tanous4a0cb852018-10-15 07:55:04 -07001752 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001753 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001754 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001755 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001756 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001757 }
1758
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001759 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001760 {
1761 if (!boost::starts_with(iface, parent + "_"))
1762 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763 return false;
1764 }
1765 else
1766 {
1767 return true;
1768 }
1769 }
1770
1771 /**
1772 * Functions triggers appropriate requests on DBus
1773 */
1774 void doGet(crow::Response &res, const crow::Request &req,
1775 const std::vector<std::string> &params) override
1776 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001777 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1778 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001779 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1780 // Check if there is required param, truly entering this shall be
1781 // impossible.
1782 if (params.size() != 2)
1783 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001784 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001785 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001786 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001787 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001788
Ed Tanous4a0cb852018-10-15 07:55:04 -07001789 const std::string &parent_iface_id = params[0];
1790 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001791 res.jsonValue["@odata.type"] =
1792 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1793 res.jsonValue["@odata.context"] =
1794 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1795 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001796
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001797 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001798 {
1799 return;
1800 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001801
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 // Get single eth interface data, and call the below callback for JSON
1803 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001804 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001805 params[1],
1806 [this, asyncResp, parent_iface_id{std::string(params[0])},
1807 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001808 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001809 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1810 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1811 const boost::container::flat_set<IPv6AddressData>
1812 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001813 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001815 parseInterfaceData(asyncResp->res.jsonValue,
1816 parent_iface_id, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001817 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001818 }
1819 else
1820 {
1821 // ... otherwise return error
1822 // TODO(Pawel)consider distinguish between non existing
1823 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001824 messages::resourceNotFound(
1825 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001828 }
1829
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 void doPatch(crow::Response &res, const crow::Request &req,
1831 const std::vector<std::string> &params) override
1832 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001833 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 if (params.size() != 2)
1835 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001836 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 return;
1838 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001839
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 const std::string &parentIfaceId = params[0];
1841 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001842
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001843 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001845 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1846 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 return;
1848 }
1849
Ed Tanous0627a2c2018-11-29 17:09:23 -08001850 bool vlanEnable = false;
1851 uint64_t vlanId = 0;
1852
1853 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1854 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001855 {
1856 return;
1857 }
1858
1859 // Get single eth interface data, and call the below callback for JSON
1860 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001861 getEthernetIfaceData(
1862 params[1],
1863 [this, asyncResp, parentIfaceId{std::string(params[0])},
1864 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1865 const bool &success, const EthernetInterfaceData &ethData,
1866 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1867 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1868 const boost::container::flat_set<IPv6AddressData>
1869 &ipv6StaticData) {
1870 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001871 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001872 auto callback =
1873 [asyncResp](const boost::system::error_code ec) {
1874 if (ec)
1875 {
1876 messages::internalError(asyncResp->res);
1877 }
1878 };
1879
1880 if (vlanEnable == true)
1881 {
1882 crow::connections::systemBus->async_method_call(
1883 std::move(callback), "xyz.openbmc_project.Network",
1884 "/xyz/openbmc_project/network/" + ifaceId,
1885 "org.freedesktop.DBus.Properties", "Set",
1886 "xyz.openbmc_project.Network.VLAN", "Id",
1887 std::variant<uint32_t>(vlanId));
1888 }
1889 else
1890 {
1891 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1892 "vlan interface";
1893 crow::connections::systemBus->async_method_call(
1894 std::move(callback), "xyz.openbmc_project.Network",
1895 std::string("/xyz/openbmc_project/network/") +
1896 ifaceId,
1897 "xyz.openbmc_project.Object.Delete", "Delete");
1898 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001899 }
1900 else
1901 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001902 // TODO(Pawel)consider distinguish between non existing
1903 // object, and other errors
1904 messages::resourceNotFound(
1905 asyncResp->res, "VLAN Network Interface", ifaceId);
1906 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001907 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001908 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001909 }
1910
1911 void doDelete(crow::Response &res, const crow::Request &req,
1912 const std::vector<std::string> &params) override
1913 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001914 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001915 if (params.size() != 2)
1916 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001917 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001918 return;
1919 }
1920
1921 const std::string &parentIfaceId = params[0];
1922 const std::string &ifaceId = params[1];
1923
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001924 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001925 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001926 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1927 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001928 return;
1929 }
1930
1931 // Get single eth interface data, and call the below callback for JSON
1932 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001933 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001934 params[1],
1935 [this, asyncResp, parentIfaceId{std::string(params[0])},
1936 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001937 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001938 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1939 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1940 const boost::container::flat_set<IPv6AddressData>
1941 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001942 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001943 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001944 auto callback =
1945 [asyncResp](const boost::system::error_code ec) {
1946 if (ec)
1947 {
1948 messages::internalError(asyncResp->res);
1949 }
1950 };
1951 crow::connections::systemBus->async_method_call(
1952 std::move(callback), "xyz.openbmc_project.Network",
1953 std::string("/xyz/openbmc_project/network/") + ifaceId,
1954 "xyz.openbmc_project.Object.Delete", "Delete");
1955 }
1956 else
1957 {
1958 // ... otherwise return error
1959 // TODO(Pawel)consider distinguish between non existing
1960 // object, and other errors
1961 messages::resourceNotFound(
1962 asyncResp->res, "VLAN Network Interface", ifaceId);
1963 }
1964 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001965 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001966};
1967
1968/**
1969 * VlanNetworkInterfaceCollection derived class for delivering
1970 * VLANNetworkInterface Collection Schema
1971 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001972class VlanNetworkInterfaceCollection : public Node
1973{
1974 public:
1975 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001976 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001977 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1978 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001979 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001980 entityPrivileges = {
1981 {boost::beast::http::verb::get, {{"Login"}}},
1982 {boost::beast::http::verb::head, {{"Login"}}},
1983 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1984 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1985 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1986 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001987 }
1988
Ed Tanous1abe55e2018-09-05 08:30:59 -07001989 private:
1990 /**
1991 * Functions triggers appropriate requests on DBus
1992 */
1993 void doGet(crow::Response &res, const crow::Request &req,
1994 const std::vector<std::string> &params) override
1995 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001996 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997 if (params.size() != 1)
1998 {
1999 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002000 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002001 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002002 }
2003
Ed Tanous4a0cb852018-10-15 07:55:04 -07002004 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002005
Ed Tanous4a0cb852018-10-15 07:55:04 -07002006 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002007 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002008 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002009 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002010 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002011 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002012 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002013 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002014 messages::internalError(asyncResp->res);
2015 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002017
2018 if (iface_list.find(rootInterfaceName) == iface_list.end())
2019 {
2020 messages::resourceNotFound(asyncResp->res,
2021 "VLanNetworkInterfaceCollection",
2022 rootInterfaceName);
2023 return;
2024 }
2025
Ed Tanous0f74e642018-11-12 15:17:05 -08002026 asyncResp->res.jsonValue["@odata.type"] =
2027 "#VLanNetworkInterfaceCollection."
2028 "VLanNetworkInterfaceCollection";
2029 asyncResp->res.jsonValue["@odata.context"] =
2030 "/redfish/v1/$metadata"
2031 "#VLanNetworkInterfaceCollection."
2032 "VLanNetworkInterfaceCollection";
2033 asyncResp->res.jsonValue["Name"] =
2034 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002035
Jason M. Billsf12894f2018-10-09 12:45:45 -07002036 nlohmann::json iface_array = nlohmann::json::array();
2037
2038 for (const std::string &iface_item : iface_list)
2039 {
2040 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2041 {
2042 iface_array.push_back(
2043 {{"@odata.id",
2044 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2045 rootInterfaceName + "/VLANs/" + iface_item}});
2046 }
2047 }
2048
Jason M. Billsf12894f2018-10-09 12:45:45 -07002049 asyncResp->res.jsonValue["Members@odata.count"] =
2050 iface_array.size();
2051 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2052 asyncResp->res.jsonValue["@odata.id"] =
2053 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2054 rootInterfaceName + "/VLANs";
2055 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002056 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002057
Ed Tanous1abe55e2018-09-05 08:30:59 -07002058 void doPost(crow::Response &res, const crow::Request &req,
2059 const std::vector<std::string> &params) override
2060 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002061 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002062 if (params.size() != 1)
2063 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002064 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002065 return;
2066 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002067 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002068 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002069 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2070 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002071 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002072 return;
2073 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002074 // Need both vlanId and vlanEnable to service this request
2075 if (!vlanId)
2076 {
2077 messages::propertyMissing(asyncResp->res, "VLANId");
2078 }
2079 if (!vlanEnable)
2080 {
2081 messages::propertyMissing(asyncResp->res, "VLANEnable");
2082 }
2083 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2084 {
2085 return;
2086 }
2087
Ed Tanous4a0cb852018-10-15 07:55:04 -07002088 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002089 auto callback = [asyncResp](const boost::system::error_code ec) {
2090 if (ec)
2091 {
2092 // TODO(ed) make more consistent error messages based on
2093 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002094 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002095 return;
2096 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002097 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002098 };
2099 crow::connections::systemBus->async_method_call(
2100 std::move(callback), "xyz.openbmc_project.Network",
2101 "/xyz/openbmc_project/network",
2102 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002103 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002104 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002105};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002106} // namespace redfish