blob: 2375d683e782e579769f057c025dc8ca0d51cf1c [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;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800103 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100104};
105
Ed Tanous4a0cb852018-10-15 07:55:04 -0700106// Helper function that changes bits netmask notation (i.e. /24)
107// into full dot notation
108inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700110 uint32_t value = 0xffffffff << (32 - bits);
111 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
112 std::to_string((value >> 16) & 0xff) + "." +
113 std::to_string((value >> 8) & 0xff) + "." +
114 std::to_string(value & 0xff);
115 return netmask;
116}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100117
Ed Tanous4a0cb852018-10-15 07:55:04 -0700118inline std::string
119 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
120 bool isIPv4)
121{
122 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700124 return "Static";
125 }
126 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
127 {
128 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700130 return "IPv4LinkLocal";
131 }
132 else
133 {
134 return "LinkLocal";
135 }
136 }
137 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
138 {
139 if (isIPv4)
140 {
141 return "DHCP";
142 }
143 else
144 {
145 return "DHCPv6";
146 }
147 }
148 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
149 {
150 return "SLAAC";
151 }
152 return "";
153}
154
Ed Tanous4c9afe42019-05-03 16:59:57 -0700155inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700156 const GetManagedObjects &dbus_data,
157 EthernetInterfaceData &ethData)
158{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700159 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700160 for (const auto &objpath : dbus_data)
161 {
Ed Tanous029573d2019-02-01 10:57:49 -0800162 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700163 {
Ed Tanous029573d2019-02-01 10:57:49 -0800164 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700166 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700167 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700169 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700171 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700173 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800174 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700175 if (mac != nullptr)
176 {
177 ethData.mac_address = *mac;
178 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700180 }
181 }
182 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
183 {
184 for (const auto &propertyPair : ifacePair.second)
185 {
186 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800188 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800189 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700190 if (id != nullptr)
191 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500192 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700193 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700195 }
196 }
197 else if (ifacePair.first ==
198 "xyz.openbmc_project.Network.EthernetInterface")
199 {
200 for (const auto &propertyPair : ifacePair.second)
201 {
202 if (propertyPair.first == "AutoNeg")
203 {
204 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800205 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700206 if (auto_neg != nullptr)
207 {
208 ethData.auto_neg = *auto_neg;
209 }
210 }
211 else if (propertyPair.first == "Speed")
212 {
213 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800214 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700215 if (speed != nullptr)
216 {
217 ethData.speed = *speed;
218 }
219 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500220 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700221 {
Ed Tanous029573d2019-02-01 10:57:49 -0800222 const std::vector<std::string> *nameservers =
223 sdbusplus::message::variant_ns::get_if<
224 std::vector<std::string>>(
225 &propertyPair.second);
226 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700227 {
Ed Tanous029573d2019-02-01 10:57:49 -0800228 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700229 }
230 }
manojkiraneda2a133282019-02-19 13:09:43 +0530231 else if (propertyPair.first == "DHCPEnabled")
232 {
233 const bool *DHCPEnabled =
234 std::get_if<bool>(&propertyPair.second);
235 if (DHCPEnabled != nullptr)
236 {
237 ethData.DHCPEnabled = *DHCPEnabled;
238 }
239 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800240 else if (propertyPair.first == "DomainName")
241 {
242 const std::vector<std::string> *domainNames =
243 sdbusplus::message::variant_ns::get_if<
244 std::vector<std::string>>(
245 &propertyPair.second);
246 if (domainNames != nullptr)
247 {
248 ethData.domainnames = std::move(*domainNames);
249 }
250 }
Ed Tanous029573d2019-02-01 10:57:49 -0800251 }
252 }
253 }
254 // System configuration shows up in the global namespace, so no need
255 // to check eth number
256 if (ifacePair.first ==
257 "xyz.openbmc_project.Network.SystemConfiguration")
258 {
259 for (const auto &propertyPair : ifacePair.second)
260 {
261 if (propertyPair.first == "HostName")
262 {
263 const std::string *hostname =
264 sdbusplus::message::variant_ns::get_if<std::string>(
265 &propertyPair.second);
266 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700267 {
Ed Tanous029573d2019-02-01 10:57:49 -0800268 ethData.hostname = *hostname;
269 }
270 }
271 else if (propertyPair.first == "DefaultGateway")
272 {
273 const std::string *defaultGateway =
274 sdbusplus::message::variant_ns::get_if<std::string>(
275 &propertyPair.second);
276 if (defaultGateway != nullptr)
277 {
278 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700279 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500281 else if (propertyPair.first == "DefaultGateway6")
282 {
283 const std::string *defaultGateway6 =
284 sdbusplus::message::variant_ns::get_if<std::string>(
285 &propertyPair.second);
286 if (defaultGateway6 != nullptr)
287 {
288 ethData.ipv6_default_gateway = *defaultGateway6;
289 }
290 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 }
292 }
293 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700295 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700296}
297
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500298// Helper function that extracts data for single ethernet ipv6 address
299inline void extractIPV6Data(
300 const std::string &ethiface_id, const GetManagedObjects &dbus_data,
301 boost::container::flat_set<IPv6AddressData> &ipv6_config,
302 boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
303{
304 const std::string ipv6PathStart =
305 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
306
307 // Since there might be several IPv6 configurations aligned with
308 // single ethernet interface, loop over all of them
309 for (const auto &objpath : dbus_data)
310 {
311 // Check if proper pattern for object path appears
312 if (boost::starts_with(objpath.first.str, ipv6PathStart))
313 {
314 for (auto &interface : objpath.second)
315 {
316 if (interface.first == "xyz.openbmc_project.Network.IP")
317 {
318 // Instance IPv6AddressData structure, and set as
319 // appropriate
320 std::pair<
321 boost::container::flat_set<IPv6AddressData>::iterator,
322 bool>
323 it = ipv6_config.insert(
324 {objpath.first.str.substr(ipv6PathStart.size())});
325 IPv6AddressData &ipv6_address = *it.first;
326 for (auto &property : interface.second)
327 {
328 if (property.first == "Address")
329 {
330 const std::string *address =
331 std::get_if<std::string>(&property.second);
332 if (address != nullptr)
333 {
334 ipv6_address.address = *address;
335 }
336 }
337 else if (property.first == "Origin")
338 {
339 const std::string *origin =
340 std::get_if<std::string>(&property.second);
341 if (origin != nullptr)
342 {
343 ipv6_address.origin =
344 translateAddressOriginDbusToRedfish(*origin,
345 false);
346 }
347 }
348 else if (property.first == "PrefixLength")
349 {
350 const uint8_t *prefix =
351 std::get_if<uint8_t>(&property.second);
352 if (prefix != nullptr)
353 {
354 ipv6_address.prefixLength = *prefix;
355 }
356 }
357 else
358 {
359 BMCWEB_LOG_ERROR
360 << "Got extra property: " << property.first
361 << " on the " << objpath.first.str << " object";
362 }
363 }
364 if (ipv6_address.origin == "Static")
365 {
366 std::pair<boost::container::flat_set<
367 IPv6AddressData>::iterator,
368 bool>
369 iter = ipv6_static_config.insert(
370 {objpath.first.str.substr(
371 ipv6PathStart.size())});
372 IPv6AddressData &ipv6_static_address = *iter.first;
373
374 ipv6_static_address.address = ipv6_address.address;
375 ipv6_static_address.prefixLength =
376 ipv6_address.prefixLength;
377 }
378 }
379 }
380 }
381 }
382}
383
Ed Tanous4a0cb852018-10-15 07:55:04 -0700384// Helper function that extracts data for single ethernet ipv4 address
385inline void
386 extractIPData(const std::string &ethiface_id,
387 const GetManagedObjects &dbus_data,
388 boost::container::flat_set<IPv4AddressData> &ipv4_config)
389{
390 const std::string ipv4PathStart =
391 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
392
393 // Since there might be several IPv4 configurations aligned with
394 // single ethernet interface, loop over all of them
395 for (const auto &objpath : dbus_data)
396 {
397 // Check if proper pattern for object path appears
398 if (boost::starts_with(objpath.first.str, ipv4PathStart))
399 {
400 for (auto &interface : objpath.second)
401 {
402 if (interface.first == "xyz.openbmc_project.Network.IP")
403 {
404 // Instance IPv4AddressData structure, and set as
405 // appropriate
406 std::pair<
407 boost::container::flat_set<IPv4AddressData>::iterator,
408 bool>
409 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000410 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700411 IPv4AddressData &ipv4_address = *it.first;
412 for (auto &property : interface.second)
413 {
414 if (property.first == "Address")
415 {
416 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800417 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700418 if (address != nullptr)
419 {
420 ipv4_address.address = *address;
421 }
422 }
423 else if (property.first == "Gateway")
424 {
425 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800426 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700427 if (gateway != nullptr)
428 {
429 ipv4_address.gateway = *gateway;
430 }
431 }
432 else if (property.first == "Origin")
433 {
434 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800435 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700436 if (origin != nullptr)
437 {
438 ipv4_address.origin =
439 translateAddressOriginDbusToRedfish(*origin,
440 true);
441 }
442 }
443 else if (property.first == "PrefixLength")
444 {
445 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800446 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700447 if (mask != nullptr)
448 {
449 // convert it to the string
450 ipv4_address.netmask = getNetmask(*mask);
451 }
452 }
453 else
454 {
455 BMCWEB_LOG_ERROR
456 << "Got extra property: " << property.first
457 << " on the " << objpath.first.str << " object";
458 }
459 }
460 // Check if given address is local, or global
461 ipv4_address.linktype =
462 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700463 ? LinkType::Local
464 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700465 }
466 }
467 }
468 }
469}
470
471/**
472 * @brief Sets given Id on the given VLAN interface through D-Bus
473 *
474 * @param[in] ifaceId Id of VLAN interface that should be modified
475 * @param[in] inputVlanId New ID of the VLAN
476 * @param[in] callback Function that will be called after the operation
477 *
478 * @return None.
479 */
480template <typename CallbackFunc>
481void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
482 CallbackFunc &&callback)
483{
484 crow::connections::systemBus->async_method_call(
485 callback, "xyz.openbmc_project.Network",
486 std::string("/xyz/openbmc_project/network/") + ifaceId,
487 "org.freedesktop.DBus.Properties", "Set",
488 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800489 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700490}
491
492/**
493 * @brief Helper function that verifies IP address to check if it is in
494 * proper format. If bits pointer is provided, also calculates active
495 * bit count for Subnet Mask.
496 *
497 * @param[in] ip IP that will be verified
498 * @param[out] bits Calculated mask in bits notation
499 *
500 * @return true in case of success, false otherwise
501 */
502inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
503 uint8_t *bits = nullptr)
504{
505 std::vector<std::string> bytesInMask;
506
507 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508
509 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700510 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700512 return false;
513 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514
Ed Tanous4a0cb852018-10-15 07:55:04 -0700515 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700517 *bits = 0;
518 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519
Ed Tanous4a0cb852018-10-15 07:55:04 -0700520 char *endPtr;
521 long previousValue = 255;
522 bool firstZeroInByteHit;
523 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700525 if (byte.empty())
526 {
527 return false;
528 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529
Ed Tanous4a0cb852018-10-15 07:55:04 -0700530 // Use strtol instead of stroi to avoid exceptions
531 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532
Ed Tanous4a0cb852018-10-15 07:55:04 -0700533 // endPtr should point to the end of the string, otherwise given string
534 // is not 100% number
535 if (*endPtr != '\0')
536 {
537 return false;
538 }
539
540 // Value should be contained in byte
541 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 {
543 return false;
544 }
545
546 if (bits != nullptr)
547 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548 // Mask has to be continuous between bytes
549 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 {
551 return false;
552 }
553
Ed Tanous4a0cb852018-10-15 07:55:04 -0700554 // Mask has to be continuous inside bytes
555 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556
Ed Tanous4a0cb852018-10-15 07:55:04 -0700557 // Count bits
558 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700559 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700560 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700562 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700564 // Continuity not preserved
565 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 }
567 else
568 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700569 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570 }
571 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 else
573 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700574 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700576 }
577 }
578
579 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 }
581
Ed Tanous4a0cb852018-10-15 07:55:04 -0700582 return true;
583}
584
585/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000586 * @brief Changes IPv4 address type property (Address, Gateway)
587 *
588 * @param[in] ifaceId Id of interface whose IP should be modified
589 * @param[in] ipIdx Index of IP in input array that should be modified
590 * @param[in] ipHash DBus Hash id of modified IP
591 * @param[in] name Name of field in JSON representation
592 * @param[in] newValue New value that should be written
593 * @param[io] asyncResp Response object that will be returned to client
594 *
595 * @return true if give IP is valid and has been sent do D-Bus, false
596 * otherwise
597 */
598inline void changeIPv4AddressProperty(
599 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
600 const std::string &name, const std::string &newValue,
601 const std::shared_ptr<AsyncResp> asyncResp)
602{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700603 auto callback =
604 [asyncResp, ipIdx, name{std::string(name)},
605 newValue{std::move(newValue)}](const boost::system::error_code ec) {
606 if (ec)
607 {
608 messages::internalError(asyncResp->res);
609 }
610 };
Ed Tanousb01bf292019-03-25 19:25:26 +0000611
612 crow::connections::systemBus->async_method_call(
613 std::move(callback), "xyz.openbmc_project.Network",
614 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
615 "org.freedesktop.DBus.Properties", "Set",
616 "xyz.openbmc_project.Network.IP", name,
617 std::variant<std::string>(newValue));
618}
619
620/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700621 * @brief Modifies SubnetMask for given IP
622 *
623 * @param[in] ifaceId Id of interface whose IP should be modified
624 * @param[in] ipIdx Index of IP in input array that should be
625 * modified
626 * @param[in] ipHash DBus Hash id of modified IP
Ed Tanous4a0cb852018-10-15 07:55:04 -0700627 * @param[in] newValue Mask as PrefixLength in bitcount
628 * @param[io] asyncResp Response object that will be returned to client
629 *
630 * @return None
631 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000632inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700633 const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700634 uint8_t &newValue,
635 std::shared_ptr<AsyncResp> asyncResp)
636{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700637 auto callback = [asyncResp, ipIdx](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700638 if (ec)
639 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800640 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700641 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700642 };
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
Ed Tanous4a0cb852018-10-15 07:55:04 -0700656 * @param[in] ipHash DBus Hash id of IP that should be deleted
657 * @param[io] asyncResp Response object that will be returned to client
658 *
659 * @return None
660 */
661inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700662 const std::shared_ptr<AsyncResp> asyncResp)
663{
664 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700665 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 if (ec)
667 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800668 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100669 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700670 },
671 "xyz.openbmc_project.Network",
672 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
673 "xyz.openbmc_project.Object.Delete", "Delete");
674}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675
Ed Tanous4a0cb852018-10-15 07:55:04 -0700676/**
677 * @brief Creates IPv4 with given data
678 *
679 * @param[in] ifaceId Id of interface whose IP should be deleted
680 * @param[in] ipIdx Index of IP in input array that should be deleted
681 * @param[in] ipHash DBus Hash id of IP that should be deleted
682 * @param[io] asyncResp Response object that will be returned to client
683 *
684 * @return None
685 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000686inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
687 uint8_t subnetMask, const std::string &gateway,
688 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700689 std::shared_ptr<AsyncResp> asyncResp)
690{
Ed Tanous43b761d2019-02-13 20:10:56 -0800691 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700692 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800694 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 };
697
Ed Tanous4a0cb852018-10-15 07:55:04 -0700698 crow::connections::systemBus->async_method_call(
699 std::move(createIpHandler), "xyz.openbmc_project.Network",
700 "/xyz/openbmc_project/network/" + ifaceId,
701 "xyz.openbmc_project.Network.IP.Create", "IP",
702 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
703 gateway);
704}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500705
706/**
707 * @brief Deletes given IPv6
708 *
709 * @param[in] ifaceId Id of interface whose IP should be deleted
710 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500711 * @param[io] asyncResp Response object that will be returned to client
712 *
713 * @return None
714 */
715inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500716 const std::shared_ptr<AsyncResp> asyncResp)
717{
718 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700719 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500720 if (ec)
721 {
722 messages::internalError(asyncResp->res);
723 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500724 },
725 "xyz.openbmc_project.Network",
726 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
727 "xyz.openbmc_project.Object.Delete", "Delete");
728}
729
730/**
731 * @brief Creates IPv6 with given data
732 *
733 * @param[in] ifaceId Id of interface whose IP should be added
734 * @param[in] ipIdx Index of IP in input array that should be added
735 * @param[in] prefixLength Prefix length that needs to be added
736 * @param[in] address IP address that needs to be added
737 * @param[io] asyncResp Response object that will be returned to client
738 *
739 * @return None
740 */
741inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
742 uint8_t prefixLength, const std::string &address,
743 std::shared_ptr<AsyncResp> asyncResp)
744{
745 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
746 if (ec)
747 {
748 messages::internalError(asyncResp->res);
749 }
750 };
751 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
752 // does not have assosiated gateway property
753 crow::connections::systemBus->async_method_call(
754 std::move(createIpHandler), "xyz.openbmc_project.Network",
755 "/xyz/openbmc_project/network/" + ifaceId,
756 "xyz.openbmc_project.Network.IP.Create", "IP",
757 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
758 "");
759}
760
manojkiraneda2a133282019-02-19 13:09:43 +0530761using GetAllPropertiesType =
762 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
763
764inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
765{
766 auto getConfig = [asyncResp](const boost::system::error_code error_code,
767 const GetAllPropertiesType &dbus_data) {
768 if (error_code)
769 {
770 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
771 messages::internalError(asyncResp->res);
772 return;
773 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500774 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530775 for (const auto &property : dbus_data)
776 {
777 auto value =
778 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
779
780 if (value == nullptr)
781 {
782 continue;
783 }
784 if (property.first == "DNSEnabled")
785 {
786 DHCPConfigTypeJson["UseDNSServers"] = *value;
787 }
788 else if (property.first == "HostNameEnabled")
789 {
790 DHCPConfigTypeJson["UseDomainName"] = *value;
791 }
792 else if (property.first == "NTPEnabled")
793 {
794 DHCPConfigTypeJson["UseNTPServers"] = *value;
795 }
796 }
797 };
798 crow::connections::systemBus->async_method_call(
799 std::move(getConfig), "xyz.openbmc_project.Network",
800 "/xyz/openbmc_project/network/config/dhcp",
801 "org.freedesktop.DBus.Properties", "GetAll",
802 "xyz.openbmc_project.Network.DHCPConfiguration");
803}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804
Ed Tanous4a0cb852018-10-15 07:55:04 -0700805/**
806 * Function that retrieves all properties for given Ethernet Interface
807 * Object
808 * from EntityManager Network Manager
809 * @param ethiface_id a eth interface id to query on DBus
810 * @param callback a function that shall be called to convert Dbus output
811 * into JSON
812 */
813template <typename CallbackFunc>
814void getEthernetIfaceData(const std::string &ethiface_id,
815 CallbackFunc &&callback)
816{
817 crow::connections::systemBus->async_method_call(
818 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
819 const boost::system::error_code error_code,
820 const GetManagedObjects &resp) {
821 EthernetInterfaceData ethData{};
822 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500823 boost::container::flat_set<IPv6AddressData> ipv6Data;
824 boost::container::flat_set<IPv6AddressData> ipv6StaticData;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700825
826 if (error_code)
827 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500828 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700829 return;
830 }
831
Ed Tanous4c9afe42019-05-03 16:59:57 -0700832 bool found =
833 extractEthernetInterfaceData(ethiface_id, resp, ethData);
834 if (!found)
835 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500836 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700837 return;
838 }
839
Ed Tanous4a0cb852018-10-15 07:55:04 -0700840 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700841 // Fix global GW
842 for (IPv4AddressData &ipv4 : ipv4Data)
843 {
844 if ((ipv4.linktype == LinkType::Global) &&
845 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700847 ipv4.gateway = ethData.default_gateway;
848 }
849 }
850
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500851 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700852 // Finally make a callback with usefull data
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500853 callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700854 },
855 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
856 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
857};
858
859/**
860 * Function that retrieves all Ethernet Interfaces available through Network
861 * Manager
862 * @param callback a function that shall be called to convert Dbus output
863 * into JSON.
864 */
865template <typename CallbackFunc>
866void getEthernetIfaceList(CallbackFunc &&callback)
867{
868 crow::connections::systemBus->async_method_call(
869 [callback{std::move(callback)}](
870 const boost::system::error_code error_code,
871 GetManagedObjects &resp) {
872 // Callback requires vector<string> to retrieve all available
873 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700874 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700875 iface_list.reserve(resp.size());
876 if (error_code)
877 {
878 callback(false, iface_list);
879 return;
880 }
881
882 // Iterate over all retrieved ObjectPaths.
883 for (const auto &objpath : resp)
884 {
885 // And all interfaces available for certain ObjectPath.
886 for (const auto &interface : objpath.second)
887 {
888 // If interface is
889 // xyz.openbmc_project.Network.EthernetInterface, this is
890 // what we're looking for.
891 if (interface.first ==
892 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700894 // Cut out everyting until last "/", ...
895 const std::string &iface_id = objpath.first.str;
896 std::size_t last_pos = iface_id.rfind("/");
897 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700899 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700900 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 }
902 }
903 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700904 }
905 // Finally make a callback with useful data
906 callback(true, iface_list);
907 },
908 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
909 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100910};
911
912/**
913 * EthernetCollection derived class for delivering Ethernet Collection Schema
914 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915class EthernetCollection : public Node
916{
917 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700918 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700920 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 entityPrivileges = {
923 {boost::beast::http::verb::get, {{"Login"}}},
924 {boost::beast::http::verb::head, {{"Login"}}},
925 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
926 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
927 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
928 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
929 }
930
931 private:
932 /**
933 * Functions triggers appropriate requests on DBus
934 */
935 void doGet(crow::Response &res, const crow::Request &req,
936 const std::vector<std::string> &params) override
937 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800938 res.jsonValue["@odata.type"] =
939 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
940 res.jsonValue["@odata.context"] =
941 "/redfish/v1/"
942 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
943 res.jsonValue["@odata.id"] =
944 "/redfish/v1/Managers/bmc/EthernetInterfaces";
945 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
946 res.jsonValue["Description"] =
947 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700948 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700949 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700951 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700952 [asyncResp](
953 const bool &success,
954 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700955 if (!success)
956 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700957 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700958 return;
959 }
960
Ed Tanous4c9afe42019-05-03 16:59:57 -0700961 nlohmann::json &iface_array =
962 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700963 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500964 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700965 for (const std::string &iface_item : iface_list)
966 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500967 std::size_t found = iface_item.find(tag);
968 if (found == std::string::npos)
969 {
970 iface_array.push_back(
971 {{"@odata.id",
972 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
973 iface_item}});
974 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700975 }
976
Ed Tanous4c9afe42019-05-03 16:59:57 -0700977 asyncResp->res.jsonValue["Members@odata.count"] =
978 iface_array.size();
979 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700980 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700981 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700982 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100983};
984
985/**
986 * EthernetInterface derived class for delivering Ethernet Schema
987 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700988class EthernetInterface : public Node
989{
990 public:
991 /*
992 * Default Constructor
993 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700994 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700996 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 std::string())
998 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 entityPrivileges = {
1000 {boost::beast::http::verb::get, {{"Login"}}},
1001 {boost::beast::http::verb::head, {{"Login"}}},
1002 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1003 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1004 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1005 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001006 }
1007
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001009 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001010 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001012 asyncResp->res.jsonValue["HostName"] = hostname;
1013 crow::connections::systemBus->async_method_call(
1014 [asyncResp](const boost::system::error_code ec) {
1015 if (ec)
1016 {
1017 messages::internalError(asyncResp->res);
1018 }
1019 },
1020 "xyz.openbmc_project.Network",
1021 "/xyz/openbmc_project/network/config",
1022 "org.freedesktop.DBus.Properties", "Set",
1023 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001024 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 }
1026
Ratan Guptad5776652019-03-03 08:47:22 +05301027 void handleMACAddressPatch(const std::string &ifaceId,
1028 const std::string &macAddress,
1029 const std::shared_ptr<AsyncResp> &asyncResp)
1030 {
1031 crow::connections::systemBus->async_method_call(
1032 [asyncResp, macAddress](const boost::system::error_code ec) {
1033 if (ec)
1034 {
1035 messages::internalError(asyncResp->res);
1036 return;
1037 }
Ratan Guptad5776652019-03-03 08:47:22 +05301038 },
1039 "xyz.openbmc_project.Network",
1040 "/xyz/openbmc_project/network/" + ifaceId,
1041 "org.freedesktop.DBus.Properties", "Set",
1042 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1043 std::variant<std::string>(macAddress));
1044 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001045
Jennifer Leeda131a92019-04-24 15:13:55 -07001046 void setDHCPEnabled(const std::string &ifaceId,
1047 const std::string &propertyName, const bool &value,
1048 const std::shared_ptr<AsyncResp> asyncResp)
1049 {
1050 crow::connections::systemBus->async_method_call(
1051 [asyncResp](const boost::system::error_code ec) {
1052 if (ec)
1053 {
1054 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1055 messages::internalError(asyncResp->res);
1056 return;
1057 }
1058 },
1059 "xyz.openbmc_project.Network",
1060 "/xyz/openbmc_project/network/" + ifaceId,
1061 "org.freedesktop.DBus.Properties", "Set",
1062 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1063 std::variant<bool>{value});
1064 }
1065 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1066 const std::shared_ptr<AsyncResp> asyncResp)
1067 {
1068 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1069 crow::connections::systemBus->async_method_call(
1070 [asyncResp](const boost::system::error_code ec) {
1071 if (ec)
1072 {
1073 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1074 messages::internalError(asyncResp->res);
1075 return;
1076 }
1077 },
1078 "xyz.openbmc_project.Network",
1079 "/xyz/openbmc_project/network/config/dhcp",
1080 "org.freedesktop.DBus.Properties", "Set",
1081 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1082 std::variant<bool>{value});
1083 }
Ratan Guptad5776652019-03-03 08:47:22 +05301084
Jennifer Leeda131a92019-04-24 15:13:55 -07001085 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1086 const std::shared_ptr<AsyncResp> asyncResp)
1087 {
1088 std::optional<bool> dhcpEnabled;
1089 std::optional<bool> useDNSServers;
1090 std::optional<bool> useDomainName;
1091 std::optional<bool> useNTPServers;
1092
1093 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1094 dhcpEnabled, "UseDNSServers", useDNSServers,
1095 "UseDomainName", useDomainName,
1096 "UseNTPServers", useNTPServers))
1097 {
1098 return;
1099 }
1100
1101 if (dhcpEnabled)
1102 {
1103 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1104 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1105 }
1106
1107 if (useDNSServers)
1108 {
1109 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1110 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1111 }
1112
1113 if (useDomainName)
1114 {
1115 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1116 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1117 }
1118
1119 if (useNTPServers)
1120 {
1121 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1122 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1123 }
1124 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001125 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301126 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001127 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1128 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001129 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301130 if (!input.is_array())
1131 {
1132 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1133 "IPv4Addresses");
1134 return;
1135 }
1136
Ed Tanous4a0cb852018-10-15 07:55:04 -07001137 int entryIdx = 0;
1138 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1139 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001140 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001141 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001142 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001143 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001144
Ratan Guptaf476acb2019-03-02 16:46:57 +05301145 if (thisJson.is_null())
1146 {
1147 if (thisData != ipv4Data.end())
1148 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001149 deleteIPv4(ifaceId, thisData->id, asyncResp);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301150 thisData++;
1151 }
1152 else
1153 {
1154 messages::propertyValueFormatError(
1155 asyncResp->res, input.dump(), pathString);
1156 return;
1157 // TODO(ratagupt) Not sure about the property where value is
1158 // list and if unable to update one of the
1159 // list value then should we proceed further or
1160 // break there, would ask in the redfish forum
1161 // till then we stop processing the next list item.
1162 }
1163 entryIdx++;
1164 continue; // not an error as per the redfish spec.
1165 }
1166
Ratan Gupta9474b372019-03-01 15:13:37 +05301167 if (thisJson.empty())
1168 {
1169 if (thisData != ipv4Data.end())
1170 {
1171 thisData++;
1172 }
1173 else
1174 {
1175 messages::propertyMissing(asyncResp->res,
1176 pathString + "/Address");
1177 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301178 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301179 // list and if unable to update one of the
1180 // list value then should we proceed further or
1181 // break there, would ask in the redfish forum
1182 // till then we stop processing the next list item.
1183 }
1184 entryIdx++;
1185 continue; // not an error as per the redfish spec.
1186 }
1187
Ed Tanous537174c2018-12-10 15:09:31 -08001188 std::optional<std::string> address;
Ed Tanous537174c2018-12-10 15:09:31 -08001189 std::optional<std::string> subnetMask;
1190 std::optional<std::string> gateway;
1191
1192 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
Johnathan Mantey7e27d832019-06-11 10:31:56 -07001193 address, "SubnetMask", subnetMask,
1194 "Gateway", gateway))
Ed Tanous537174c2018-12-10 15:09:31 -08001195 {
1196 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001197 }
1198
Ed Tanous537174c2018-12-10 15:09:31 -08001199 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001200 {
Ed Tanous537174c2018-12-10 15:09:31 -08001201 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001202 {
Ed Tanous537174c2018-12-10 15:09:31 -08001203 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001204 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001205 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001206 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001208
Ed Tanous537174c2018-12-10 15:09:31 -08001209 uint8_t prefixLength = 0;
1210 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001211 {
Ed Tanous537174c2018-12-10 15:09:31 -08001212 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001213 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001214 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001215 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001216 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001217 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001218 }
1219 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001220
Ed Tanous537174c2018-12-10 15:09:31 -08001221 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001222 {
Ed Tanous537174c2018-12-10 15:09:31 -08001223 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001224 {
Ed Tanous537174c2018-12-10 15:09:31 -08001225 messages::propertyValueFormatError(asyncResp->res, *gateway,
1226 pathString + "/Gateway");
1227 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001228 }
1229 }
1230
Ratan Guptaf476acb2019-03-02 16:46:57 +05301231 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001232 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301234 // Apply changes
1235 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001236 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001237 auto callback =
1238 [asyncResp](const boost::system::error_code ec) {
1239 if (ec)
1240 {
1241 messages::internalError(asyncResp->res);
1242 return;
1243 }
1244 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301245
Ed Tanous4a0cb852018-10-15 07:55:04 -07001246 crow::connections::systemBus->async_method_call(
1247 std::move(callback), "xyz.openbmc_project.Network",
1248 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1249 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301250 "org.freedesktop.DBus.Properties", "Set",
1251 "xyz.openbmc_project.Network.IP", "Address",
1252 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301254
1255 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001256 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301257 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
Johnathan Mantey286b9112019-06-10 13:38:04 -07001258 thisData->id, prefixLength,
1259 asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001260 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301261
Ratan Guptaf476acb2019-03-02 16:46:57 +05301262 if (gateway)
1263 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001264 auto callback =
1265 [asyncResp](const boost::system::error_code ec) {
1266 if (ec)
1267 {
1268 messages::internalError(asyncResp->res);
1269 return;
1270 }
1271 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301272
1273 crow::connections::systemBus->async_method_call(
1274 std::move(callback), "xyz.openbmc_project.Network",
1275 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1276 thisData->id,
1277 "org.freedesktop.DBus.Properties", "Set",
1278 "xyz.openbmc_project.Network.IP", "Gateway",
1279 std::variant<std::string>(*gateway));
1280 }
1281
Ed Tanous4a0cb852018-10-15 07:55:04 -07001282 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001283 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001284 else
1285 {
1286 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001287 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001288 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001289 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001290 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001291 continue;
1292 }
1293
Ed Tanous537174c2018-12-10 15:09:31 -08001294 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001295 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001296 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001297 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001298 continue;
1299 }
1300
Ed Tanous537174c2018-12-10 15:09:31 -08001301 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001302 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001303 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001304 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001305 continue;
1306 }
1307
Ed Tanousb01bf292019-03-25 19:25:26 +00001308 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1309 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301310
1311 nlohmann::json &ipv4AddressJson =
1312 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1313 ipv4AddressJson["Address"] = *address;
1314 ipv4AddressJson["SubnetMask"] = *subnetMask;
1315 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001316 }
1317 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001318 }
1319 }
1320
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001321 void handleStaticNameServersPatch(
1322 const std::string &ifaceId,
1323 const std::vector<std::string> &updatedStaticNameServers,
1324 const std::shared_ptr<AsyncResp> &asyncResp)
1325 {
1326 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001327 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001328 if (ec)
1329 {
1330 messages::internalError(asyncResp->res);
1331 return;
1332 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001333 },
1334 "xyz.openbmc_project.Network",
1335 "/xyz/openbmc_project/network/" + ifaceId,
1336 "org.freedesktop.DBus.Properties", "Set",
1337 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1338 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1339 }
1340
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001341 void handleIPv6StaticAddressesPatch(
1342 const std::string &ifaceId, nlohmann::json &input,
1343 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1344 const std::shared_ptr<AsyncResp> asyncResp)
1345 {
1346 if (!input.is_array())
1347 {
1348 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1349 "IPv6StaticAddresses");
1350 return;
1351 }
1352
1353 int entryIdx = 0;
1354 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1355 ipv6StaticData.begin();
1356 for (nlohmann::json &thisJson : input)
1357 {
1358 std::string pathString =
1359 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1360
1361 if (thisJson.is_null())
1362 {
1363 if (thisData != ipv6StaticData.end())
1364 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001365 deleteIPv6(ifaceId, thisData->id, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001366 thisData++;
1367 }
1368 else
1369 {
1370 messages::propertyValueFormatError(
1371 asyncResp->res, input.dump(), pathString);
1372 return;
1373 }
1374 entryIdx++;
1375 continue;
1376 }
1377
1378 if (thisJson.empty())
1379 {
1380 if (thisData != ipv6StaticData.end())
1381 {
1382 thisData++;
1383 }
1384 else
1385 {
1386 messages::propertyMissing(asyncResp->res,
1387 pathString + "/Address");
1388 return;
1389 }
1390 entryIdx++;
1391 continue;
1392 }
1393
1394 std::optional<std::string> address;
1395 std::optional<uint8_t> prefixLength;
1396
1397 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1398 address, "PrefixLength", prefixLength))
1399 {
1400 return;
1401 }
1402
1403 // if IP address exist then modify it.
1404 if (thisData != ipv6StaticData.end())
1405 {
1406 // Apply changes
1407 if (address)
1408 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001409 auto callback =
1410 [asyncResp](const boost::system::error_code ec) {
1411 if (ec)
1412 {
1413 messages::internalError(asyncResp->res);
1414 return;
1415 }
1416 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001417
1418 crow::connections::systemBus->async_method_call(
1419 std::move(callback), "xyz.openbmc_project.Network",
1420 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1421 thisData->id,
1422 "org.freedesktop.DBus.Properties", "Set",
1423 "xyz.openbmc_project.Network.IP", "Address",
1424 std::variant<std::string>(*address));
1425 }
1426
1427 if (prefixLength)
1428 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001429 auto callback =
1430 [asyncResp](const boost::system::error_code ec) {
1431 if (ec)
1432 {
1433 messages::internalError(asyncResp->res);
1434 return;
1435 }
1436 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001437
1438 crow::connections::systemBus->async_method_call(
1439 std::move(callback), "xyz.openbmc_project.Network",
1440 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1441 thisData->id,
1442 "org.freedesktop.DBus.Properties", "Set",
1443 "xyz.openbmc_project.Network.IP", "PrefixLength",
1444 std::variant<uint8_t>(*prefixLength));
1445 }
1446
1447 thisData++;
1448 }
1449 else
1450 {
1451 // Create IPv6 with provided data
1452
1453 if (!prefixLength)
1454 {
1455 messages::propertyMissing(asyncResp->res,
1456 pathString + "/PrefixLength");
1457 continue;
1458 }
1459
1460 if (!address)
1461 {
1462 messages::propertyMissing(asyncResp->res,
1463 pathString + "/Address");
1464 continue;
1465 }
1466
1467 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1468 asyncResp);
1469
1470 nlohmann::json &ipv6StaticAddressJson =
1471 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1472 ipv6StaticAddressJson["Address"] = *address;
1473 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1474 }
1475 entryIdx++;
1476 }
1477 }
1478
Ed Tanous0f74e642018-11-12 15:17:05 -08001479 void parseInterfaceData(
1480 nlohmann::json &json_response, const std::string &iface_id,
1481 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001482 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1483 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1484 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001485 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001486 json_response["Id"] = iface_id;
1487 json_response["@odata.id"] =
1488 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001489 json_response["InterfaceEnabled"] = true;
1490 if (ethData.speed == 0)
1491 {
1492 json_response["LinkStatus"] = "NoLink";
1493 json_response["Status"] = {
1494 {"Health", "OK"},
1495 {"State", "Disabled"},
1496 };
1497 }
1498 else
1499 {
1500 json_response["LinkStatus"] = "LinkUp";
1501 json_response["Status"] = {
1502 {"Health", "OK"},
1503 {"State", "Enabled"},
1504 };
1505 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001506 json_response["SpeedMbps"] = ethData.speed;
1507 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001508 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301509
Ed Tanous4a0cb852018-10-15 07:55:04 -07001510 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001511 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001512 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001513 if (!ethData.domainnames.empty())
1514 {
1515 json_response["FQDN"] =
1516 ethData.hostname + "." + ethData.domainnames[0];
1517 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001518 }
1519
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001520 json_response["VLANs"] = {
1521 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1522 iface_id + "/VLANs"}};
1523
Ed Tanous029573d2019-02-01 10:57:49 -08001524 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001525 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526
Ed Tanous4a0cb852018-10-15 07:55:04 -07001527 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001529 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1530 ipv4_array = nlohmann::json::array();
1531 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001533
1534 std::string gatewayStr = ipv4_config.gateway;
1535 if (gatewayStr.empty())
1536 {
1537 gatewayStr = "0.0.0.0";
1538 }
1539
Ed Tanous029573d2019-02-01 10:57:49 -08001540 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1541 {"SubnetMask", ipv4_config.netmask},
1542 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001543 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001545 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001546 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001547
1548 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1549 ipv6_array = nlohmann::json::array();
1550 for (auto &ipv6_config : ipv6Data)
1551 {
1552 ipv6_array.push_back({{"Address", ipv6_config.address},
1553 {"PrefixLength", ipv6_config.prefixLength},
1554 {"AddressOrigin", ipv6_config.origin}});
1555 }
1556
1557 nlohmann::json &ipv6_static_array =
1558 json_response["IPv6StaticAddresses"];
1559 ipv6_static_array = nlohmann::json::array();
1560 for (auto &ipv6_static_config : ipv6StaticData)
1561 {
1562 ipv6_static_array.push_back(
1563 {{"Address", ipv6_static_config.address},
1564 {"PrefixLength", ipv6_static_config.prefixLength}});
1565 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001566 }
1567
1568 /**
1569 * Functions triggers appropriate requests on DBus
1570 */
1571 void doGet(crow::Response &res, const crow::Request &req,
1572 const std::vector<std::string> &params) override
1573 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001574 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575 if (params.size() != 1)
1576 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001577 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 return;
1579 }
1580
Ed Tanous4a0cb852018-10-15 07:55:04 -07001581 getEthernetIfaceData(
1582 params[0],
1583 [this, asyncResp, iface_id{std::string(params[0])}](
1584 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001585 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1586 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1587 const boost::container::flat_set<IPv6AddressData>
1588 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001589 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001591 // TODO(Pawel)consider distinguish between non existing
1592 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001593 messages::resourceNotFound(asyncResp->res,
1594 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001595 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001596 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001597
1598 // because this has no dependence on the interface at this
1599 // point, it needs to be done after we know the interface
1600 // exists, not before.
1601 getDHCPConfigData(asyncResp);
1602
Ed Tanous0f74e642018-11-12 15:17:05 -08001603 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001604 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001605 asyncResp->res.jsonValue["@odata.context"] =
1606 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1607 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1608 asyncResp->res.jsonValue["Description"] =
1609 "Management Network Interface";
1610
1611 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001612 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001613 });
1614 }
1615
1616 void doPatch(crow::Response &res, const crow::Request &req,
1617 const std::vector<std::string> &params) override
1618 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001619 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001620 if (params.size() != 1)
1621 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001622 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001623 return;
1624 }
1625
Ed Tanous4a0cb852018-10-15 07:55:04 -07001626 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001628 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301629 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001630 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301631 std::optional<nlohmann::json> ipv4Addresses;
1632 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001633 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001634 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001635 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001636 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001637
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001638 if (!json_util::readJson(
1639 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Johnathan Mantey6ca6ac12019-06-10 12:21:31 -07001640 "MACAddress", macAddress, "StaticNameServers",
1641 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
1642 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
1643 nameServers, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644 {
1645 return;
1646 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301647
Jennifer Leeda131a92019-04-24 15:13:55 -07001648 if (dhcpv4)
1649 {
1650 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1651 }
1652
Ed Tanous4a0cb852018-10-15 07:55:04 -07001653 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001654 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001655 getEthernetIfaceData(
1656 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001657 [this, asyncResp, iface_id, hostname = std::move(hostname),
1658 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001659 ipv4Addresses = std::move(ipv4Addresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001660 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001661 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001662 staticNameServers = std::move(staticNameServers),
1663 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001664 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001665 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1666 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1667 const boost::container::flat_set<IPv6AddressData>
1668 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669 if (!success)
1670 {
1671 // ... otherwise return error
1672 // TODO(Pawel)consider distinguish between non existing
1673 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001674 messages::resourceNotFound(asyncResp->res,
1675 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 return;
1677 }
1678
Ed Tanous0627a2c2018-11-29 17:09:23 -08001679 if (hostname)
1680 {
1681 handleHostnamePatch(*hostname, asyncResp);
1682 }
1683
Ratan Guptad5776652019-03-03 08:47:22 +05301684 if (macAddress)
1685 {
1686 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1687 }
1688
Ed Tanous0627a2c2018-11-29 17:09:23 -08001689 if (ipv4Addresses)
1690 {
Ed Tanous537174c2018-12-10 15:09:31 -08001691 // TODO(ed) for some reason the capture of ipv4Addresses
1692 // above is returning a const value, not a non-const value.
1693 // This doesn't really work for us, as we need to be able to
1694 // efficiently move out the intermedia nlohmann::json
1695 // objects. This makes a copy of the structure, and operates
1696 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301697 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001698 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001699 }
1700
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001701 if (nameServers)
1702 {
1703 // Data.Permissions is read-only
1704 messages::propertyNotWritable(asyncResp->res,
1705 "NameServers");
1706 }
1707
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001708 if (staticNameServers)
1709 {
1710 handleStaticNameServersPatch(iface_id, *staticNameServers,
1711 asyncResp);
1712 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001713
1714 if (ipv6DefaultGateway)
1715 {
1716 messages::propertyNotWritable(asyncResp->res,
1717 "IPv6DefaultGateway");
1718 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001719
1720 if (ipv6StaticAddresses)
1721 {
1722 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1723 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1724 ipv6StaticData, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001725 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001726 });
1727 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001728};
1729
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001730/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001731 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1732 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001733 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734class VlanNetworkInterface : public Node
1735{
1736 public:
1737 /*
1738 * Default Constructor
1739 */
1740 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001742 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001743 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001744 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001746 entityPrivileges = {
1747 {boost::beast::http::verb::get, {{"Login"}}},
1748 {boost::beast::http::verb::head, {{"Login"}}},
1749 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1750 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1751 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1752 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001753 }
1754
Ed Tanous1abe55e2018-09-05 08:30:59 -07001755 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001756 void parseInterfaceData(
1757 nlohmann::json &json_response, const std::string &parent_iface_id,
1758 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001759 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1760 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1761 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001762 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001764 json_response["Id"] = iface_id;
1765 json_response["@odata.id"] =
1766 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1767 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001768
Ed Tanous4a0cb852018-10-15 07:55:04 -07001769 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001770 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001771 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001772 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001773 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001774 }
1775
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001776 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001777 {
1778 if (!boost::starts_with(iface, parent + "_"))
1779 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001780 return false;
1781 }
1782 else
1783 {
1784 return true;
1785 }
1786 }
1787
1788 /**
1789 * Functions triggers appropriate requests on DBus
1790 */
1791 void doGet(crow::Response &res, const crow::Request &req,
1792 const std::vector<std::string> &params) override
1793 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001794 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1795 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001796 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1797 // Check if there is required param, truly entering this shall be
1798 // impossible.
1799 if (params.size() != 2)
1800 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001801 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001803 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001805
Ed Tanous4a0cb852018-10-15 07:55:04 -07001806 const std::string &parent_iface_id = params[0];
1807 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001808 res.jsonValue["@odata.type"] =
1809 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1810 res.jsonValue["@odata.context"] =
1811 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1812 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001813
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001814 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001815 {
1816 return;
1817 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001818
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 // Get single eth interface data, and call the below callback for JSON
1820 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001821 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001822 params[1],
1823 [this, asyncResp, parent_iface_id{std::string(params[0])},
1824 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001825 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001826 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1827 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1828 const boost::container::flat_set<IPv6AddressData>
1829 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001830 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001831 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001832 parseInterfaceData(asyncResp->res.jsonValue,
1833 parent_iface_id, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001834 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 }
1836 else
1837 {
1838 // ... otherwise return error
1839 // TODO(Pawel)consider distinguish between non existing
1840 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001841 messages::resourceNotFound(
1842 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001843 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001845 }
1846
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 void doPatch(crow::Response &res, const crow::Request &req,
1848 const std::vector<std::string> &params) override
1849 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001850 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001851 if (params.size() != 2)
1852 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001853 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 return;
1855 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001856
Ed Tanous1abe55e2018-09-05 08:30:59 -07001857 const std::string &parentIfaceId = params[0];
1858 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001859
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001860 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001862 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1863 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001864 return;
1865 }
1866
Ed Tanous0627a2c2018-11-29 17:09:23 -08001867 bool vlanEnable = false;
1868 uint64_t vlanId = 0;
1869
1870 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1871 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001872 {
1873 return;
1874 }
1875
1876 // Get single eth interface data, and call the below callback for JSON
1877 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001878 getEthernetIfaceData(
1879 params[1],
1880 [this, asyncResp, parentIfaceId{std::string(params[0])},
1881 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1882 const bool &success, const EthernetInterfaceData &ethData,
1883 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1884 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1885 const boost::container::flat_set<IPv6AddressData>
1886 &ipv6StaticData) {
1887 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001888 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001889 auto callback =
1890 [asyncResp](const boost::system::error_code ec) {
1891 if (ec)
1892 {
1893 messages::internalError(asyncResp->res);
1894 }
1895 };
1896
1897 if (vlanEnable == true)
1898 {
1899 crow::connections::systemBus->async_method_call(
1900 std::move(callback), "xyz.openbmc_project.Network",
1901 "/xyz/openbmc_project/network/" + ifaceId,
1902 "org.freedesktop.DBus.Properties", "Set",
1903 "xyz.openbmc_project.Network.VLAN", "Id",
1904 std::variant<uint32_t>(vlanId));
1905 }
1906 else
1907 {
1908 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1909 "vlan interface";
1910 crow::connections::systemBus->async_method_call(
1911 std::move(callback), "xyz.openbmc_project.Network",
1912 std::string("/xyz/openbmc_project/network/") +
1913 ifaceId,
1914 "xyz.openbmc_project.Object.Delete", "Delete");
1915 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001916 }
1917 else
1918 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001919 // TODO(Pawel)consider distinguish between non existing
1920 // object, and other errors
1921 messages::resourceNotFound(
1922 asyncResp->res, "VLAN Network Interface", ifaceId);
1923 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001924 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001925 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001926 }
1927
1928 void doDelete(crow::Response &res, const crow::Request &req,
1929 const std::vector<std::string> &params) override
1930 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001931 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001932 if (params.size() != 2)
1933 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001934 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001935 return;
1936 }
1937
1938 const std::string &parentIfaceId = params[0];
1939 const std::string &ifaceId = params[1];
1940
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001941 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001943 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1944 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001945 return;
1946 }
1947
1948 // Get single eth interface data, and call the below callback for JSON
1949 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001950 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001951 params[1],
1952 [this, asyncResp, parentIfaceId{std::string(params[0])},
1953 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001954 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001955 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1956 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1957 const boost::container::flat_set<IPv6AddressData>
1958 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001959 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001960 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001961 auto callback =
1962 [asyncResp](const boost::system::error_code ec) {
1963 if (ec)
1964 {
1965 messages::internalError(asyncResp->res);
1966 }
1967 };
1968 crow::connections::systemBus->async_method_call(
1969 std::move(callback), "xyz.openbmc_project.Network",
1970 std::string("/xyz/openbmc_project/network/") + ifaceId,
1971 "xyz.openbmc_project.Object.Delete", "Delete");
1972 }
1973 else
1974 {
1975 // ... otherwise return error
1976 // TODO(Pawel)consider distinguish between non existing
1977 // object, and other errors
1978 messages::resourceNotFound(
1979 asyncResp->res, "VLAN Network Interface", ifaceId);
1980 }
1981 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001982 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001983};
1984
1985/**
1986 * VlanNetworkInterfaceCollection derived class for delivering
1987 * VLANNetworkInterface Collection Schema
1988 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001989class VlanNetworkInterfaceCollection : public Node
1990{
1991 public:
1992 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001993 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001994 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1995 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001996 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997 entityPrivileges = {
1998 {boost::beast::http::verb::get, {{"Login"}}},
1999 {boost::beast::http::verb::head, {{"Login"}}},
2000 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2001 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2002 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2003 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002004 }
2005
Ed Tanous1abe55e2018-09-05 08:30:59 -07002006 private:
2007 /**
2008 * Functions triggers appropriate requests on DBus
2009 */
2010 void doGet(crow::Response &res, const crow::Request &req,
2011 const std::vector<std::string> &params) override
2012 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002013 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002014 if (params.size() != 1)
2015 {
2016 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002017 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002018 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002019 }
2020
Ed Tanous4a0cb852018-10-15 07:55:04 -07002021 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002022
Ed Tanous4a0cb852018-10-15 07:55:04 -07002023 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002024 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002025 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002026 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002027 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002028 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002029 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002030 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002031 messages::internalError(asyncResp->res);
2032 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002033 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002034
2035 if (iface_list.find(rootInterfaceName) == iface_list.end())
2036 {
2037 messages::resourceNotFound(asyncResp->res,
2038 "VLanNetworkInterfaceCollection",
2039 rootInterfaceName);
2040 return;
2041 }
2042
Ed Tanous0f74e642018-11-12 15:17:05 -08002043 asyncResp->res.jsonValue["@odata.type"] =
2044 "#VLanNetworkInterfaceCollection."
2045 "VLanNetworkInterfaceCollection";
2046 asyncResp->res.jsonValue["@odata.context"] =
2047 "/redfish/v1/$metadata"
2048 "#VLanNetworkInterfaceCollection."
2049 "VLanNetworkInterfaceCollection";
2050 asyncResp->res.jsonValue["Name"] =
2051 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002052
Jason M. Billsf12894f2018-10-09 12:45:45 -07002053 nlohmann::json iface_array = nlohmann::json::array();
2054
2055 for (const std::string &iface_item : iface_list)
2056 {
2057 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2058 {
2059 iface_array.push_back(
2060 {{"@odata.id",
2061 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2062 rootInterfaceName + "/VLANs/" + iface_item}});
2063 }
2064 }
2065
Jason M. Billsf12894f2018-10-09 12:45:45 -07002066 asyncResp->res.jsonValue["Members@odata.count"] =
2067 iface_array.size();
2068 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2069 asyncResp->res.jsonValue["@odata.id"] =
2070 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2071 rootInterfaceName + "/VLANs";
2072 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002073 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002074
Ed Tanous1abe55e2018-09-05 08:30:59 -07002075 void doPost(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 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002081 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002082 return;
2083 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002084 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002085 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002086 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2087 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002089 return;
2090 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002091 // Need both vlanId and vlanEnable to service this request
2092 if (!vlanId)
2093 {
2094 messages::propertyMissing(asyncResp->res, "VLANId");
2095 }
2096 if (!vlanEnable)
2097 {
2098 messages::propertyMissing(asyncResp->res, "VLANEnable");
2099 }
2100 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2101 {
2102 return;
2103 }
2104
Ed Tanous4a0cb852018-10-15 07:55:04 -07002105 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002106 auto callback = [asyncResp](const boost::system::error_code ec) {
2107 if (ec)
2108 {
2109 // TODO(ed) make more consistent error messages based on
2110 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002111 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002112 return;
2113 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002114 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002115 };
2116 crow::connections::systemBus->async_method_call(
2117 std::move(callback), "xyz.openbmc_project.Network",
2118 "/xyz/openbmc_project/network",
2119 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002120 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002121 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002122};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002123} // namespace redfish