blob: ff37330c4b9f1065a6356c2bd1306943318d713b [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
Johnathan Mantey01784822019-06-18 12:44:21 -0700299inline void
300 extractIPV6Data(const std::string &ethiface_id,
301 const GetManagedObjects &dbus_data,
302 boost::container::flat_set<IPv6AddressData> &ipv6_config)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500303{
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 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500364 }
365 }
366 }
367 }
368}
369
Ed Tanous4a0cb852018-10-15 07:55:04 -0700370// Helper function that extracts data for single ethernet ipv4 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700371inline void
372 extractIPData(const std::string &ethiface_id,
373 const GetManagedObjects &dbus_data,
374 boost::container::flat_set<IPv4AddressData> &ipv4_config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700375{
376 const std::string ipv4PathStart =
377 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
378
379 // Since there might be several IPv4 configurations aligned with
380 // single ethernet interface, loop over all of them
381 for (const auto &objpath : dbus_data)
382 {
383 // Check if proper pattern for object path appears
384 if (boost::starts_with(objpath.first.str, ipv4PathStart))
385 {
386 for (auto &interface : objpath.second)
387 {
388 if (interface.first == "xyz.openbmc_project.Network.IP")
389 {
390 // Instance IPv4AddressData structure, and set as
391 // appropriate
392 std::pair<
393 boost::container::flat_set<IPv4AddressData>::iterator,
394 bool>
395 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000396 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700397 IPv4AddressData &ipv4_address = *it.first;
398 for (auto &property : interface.second)
399 {
400 if (property.first == "Address")
401 {
402 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800403 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700404 if (address != nullptr)
405 {
406 ipv4_address.address = *address;
407 }
408 }
409 else if (property.first == "Gateway")
410 {
411 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800412 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700413 if (gateway != nullptr)
414 {
415 ipv4_address.gateway = *gateway;
416 }
417 }
418 else if (property.first == "Origin")
419 {
420 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800421 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700422 if (origin != nullptr)
423 {
424 ipv4_address.origin =
425 translateAddressOriginDbusToRedfish(*origin,
426 true);
427 }
428 }
429 else if (property.first == "PrefixLength")
430 {
431 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800432 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700433 if (mask != nullptr)
434 {
435 // convert it to the string
436 ipv4_address.netmask = getNetmask(*mask);
437 }
438 }
439 else
440 {
441 BMCWEB_LOG_ERROR
442 << "Got extra property: " << property.first
443 << " on the " << objpath.first.str << " object";
444 }
445 }
446 // Check if given address is local, or global
447 ipv4_address.linktype =
448 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700449 ? LinkType::Local
450 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700451 }
452 }
453 }
454 }
455}
456
457/**
458 * @brief Sets given Id on the given VLAN interface through D-Bus
459 *
460 * @param[in] ifaceId Id of VLAN interface that should be modified
461 * @param[in] inputVlanId New ID of the VLAN
462 * @param[in] callback Function that will be called after the operation
463 *
464 * @return None.
465 */
466template <typename CallbackFunc>
467void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
468 CallbackFunc &&callback)
469{
470 crow::connections::systemBus->async_method_call(
471 callback, "xyz.openbmc_project.Network",
472 std::string("/xyz/openbmc_project/network/") + ifaceId,
473 "org.freedesktop.DBus.Properties", "Set",
474 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800475 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700476}
477
478/**
479 * @brief Helper function that verifies IP address to check if it is in
480 * proper format. If bits pointer is provided, also calculates active
481 * bit count for Subnet Mask.
482 *
483 * @param[in] ip IP that will be verified
484 * @param[out] bits Calculated mask in bits notation
485 *
486 * @return true in case of success, false otherwise
487 */
488inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
489 uint8_t *bits = nullptr)
490{
491 std::vector<std::string> bytesInMask;
492
493 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494
495 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700496 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700498 return false;
499 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500
Ed Tanous4a0cb852018-10-15 07:55:04 -0700501 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700503 *bits = 0;
504 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505
Ed Tanous4a0cb852018-10-15 07:55:04 -0700506 char *endPtr;
507 long previousValue = 255;
508 bool firstZeroInByteHit;
509 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700511 if (byte.empty())
512 {
513 return false;
514 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515
Ed Tanous4a0cb852018-10-15 07:55:04 -0700516 // Use strtol instead of stroi to avoid exceptions
517 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518
Ed Tanous4a0cb852018-10-15 07:55:04 -0700519 // endPtr should point to the end of the string, otherwise given string
520 // is not 100% number
521 if (*endPtr != '\0')
522 {
523 return false;
524 }
525
526 // Value should be contained in byte
527 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 {
529 return false;
530 }
531
532 if (bits != nullptr)
533 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700534 // Mask has to be continuous between bytes
535 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 {
537 return false;
538 }
539
Ed Tanous4a0cb852018-10-15 07:55:04 -0700540 // Mask has to be continuous inside bytes
541 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542
Ed Tanous4a0cb852018-10-15 07:55:04 -0700543 // Count bits
544 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700546 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700550 // Continuity not preserved
551 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 }
553 else
554 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700555 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 }
557 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 else
559 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700560 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700562 }
563 }
564
565 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 }
567
Ed Tanous4a0cb852018-10-15 07:55:04 -0700568 return true;
569}
570
571/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700572 * @brief Deletes given IPv4 interface
Ed Tanous4a0cb852018-10-15 07:55:04 -0700573 *
574 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700575 * @param[in] ipHash DBus Hash id of IP that should be deleted
576 * @param[io] asyncResp Response object that will be returned to client
577 *
578 * @return None
579 */
580inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700581 const std::shared_ptr<AsyncResp> asyncResp)
582{
583 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700584 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 if (ec)
586 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800587 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100588 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700589 },
590 "xyz.openbmc_project.Network",
591 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
592 "xyz.openbmc_project.Object.Delete", "Delete");
593}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594
Ed Tanous4a0cb852018-10-15 07:55:04 -0700595/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700596 * @brief Creates a static IPv4 entry
Ed Tanous4a0cb852018-10-15 07:55:04 -0700597 *
Johnathan Mantey01784822019-06-18 12:44:21 -0700598 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
599 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
600 * @param[in] gateway IPv4 address of this interfaces gateway
601 * @param[in] address IPv4 address to assign to this interface
602 * @param[io] asyncResp Response object that will be returned to client
Ed Tanous4a0cb852018-10-15 07:55:04 -0700603 *
604 * @return None
605 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000606inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
Johnathan Mantey01784822019-06-18 12:44:21 -0700607 uint8_t prefixLength, const std::string &gateway,
Ed Tanousb01bf292019-03-25 19:25:26 +0000608 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700609 std::shared_ptr<AsyncResp> asyncResp)
610{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700611 crow::connections::systemBus->async_method_call(
Johnathan Mantey01784822019-06-18 12:44:21 -0700612 [asyncResp](const boost::system::error_code ec) {
613 if (ec)
614 {
615 messages::internalError(asyncResp->res);
616 }
617 },
618 "xyz.openbmc_project.Network",
Ed Tanous4a0cb852018-10-15 07:55:04 -0700619 "/xyz/openbmc_project/network/" + ifaceId,
620 "xyz.openbmc_project.Network.IP.Create", "IP",
Johnathan Mantey01784822019-06-18 12:44:21 -0700621 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, prefixLength,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700622 gateway);
623}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500624
625/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700626 * @brief Deletes the IPv4 entry for this interface and creates a replacement
627 * static IPv4 entry
628 *
629 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
630 * @param[in] id The unique hash entry identifying the DBus entry
631 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
632 * @param[in] gateway IPv4 address of this interfaces gateway
633 * @param[in] address IPv4 address to assign to this interface
634 * @param[io] asyncResp Response object that will be returned to client
635 *
636 * @return None
637 */
638inline void deleteAndCreateIPv4(const std::string &ifaceId,
639 const std::string &id, uint8_t prefixLength,
640 const std::string &gateway,
641 const std::string &address,
642 std::shared_ptr<AsyncResp> asyncResp)
643{
644 crow::connections::systemBus->async_method_call(
645 [asyncResp, ifaceId, address, prefixLength,
646 gateway](const boost::system::error_code ec) {
647 if (ec)
648 {
649 messages::internalError(asyncResp->res);
650 }
651 crow::connections::systemBus->async_method_call(
652 [asyncResp](const boost::system::error_code ec) {
653 if (ec)
654 {
655 messages::internalError(asyncResp->res);
656 }
657 },
658 "xyz.openbmc_project.Network",
659 "/xyz/openbmc_project/network/" + ifaceId,
660 "xyz.openbmc_project.Network.IP.Create", "IP",
661 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address,
662 prefixLength, gateway);
663 },
664 "xyz.openbmc_project.Network",
665 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + id,
666 "xyz.openbmc_project.Object.Delete", "Delete");
667}
668
669/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500670 * @brief Deletes given IPv6
671 *
672 * @param[in] ifaceId Id of interface whose IP should be deleted
673 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500674 * @param[io] asyncResp Response object that will be returned to client
675 *
676 * @return None
677 */
678inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500679 const std::shared_ptr<AsyncResp> asyncResp)
680{
681 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700682 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500683 if (ec)
684 {
685 messages::internalError(asyncResp->res);
686 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500687 },
688 "xyz.openbmc_project.Network",
689 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
690 "xyz.openbmc_project.Object.Delete", "Delete");
691}
692
693/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700694 * @brief Deletes the IPv6 entry for this interface and creates a replacement
695 * static IPv6 entry
696 *
697 * @param[in] ifaceId Id of interface upon which to create the IPv6 entry
698 * @param[in] id The unique hash entry identifying the DBus entry
699 * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
700 * @param[in] address IPv6 address to assign to this interface
701 * @param[io] asyncResp Response object that will be returned to client
702 *
703 * @return None
704 */
705inline void deleteAndCreateIPv6(const std::string &ifaceId,
706 const std::string &id, uint8_t prefixLength,
707 const std::string &address,
708 std::shared_ptr<AsyncResp> asyncResp)
709{
710 crow::connections::systemBus->async_method_call(
711 [asyncResp, ifaceId, address,
712 prefixLength](const boost::system::error_code ec) {
713 if (ec)
714 {
715 messages::internalError(asyncResp->res);
716 }
717 crow::connections::systemBus->async_method_call(
718 [asyncResp](const boost::system::error_code ec) {
719 if (ec)
720 {
721 messages::internalError(asyncResp->res);
722 }
723 },
724 "xyz.openbmc_project.Network",
725 "/xyz/openbmc_project/network/" + ifaceId,
726 "xyz.openbmc_project.Network.IP.Create", "IP",
727 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address,
728 prefixLength, "");
729 },
730 "xyz.openbmc_project.Network",
731 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + id,
732 "xyz.openbmc_project.Object.Delete", "Delete");
733}
734
735/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500736 * @brief Creates IPv6 with given data
737 *
738 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500739 * @param[in] prefixLength Prefix length that needs to be added
740 * @param[in] address IP address that needs to be added
741 * @param[io] asyncResp Response object that will be returned to client
742 *
743 * @return None
744 */
Johnathan Mantey01784822019-06-18 12:44:21 -0700745inline void createIPv6(const std::string &ifaceId, uint8_t prefixLength,
746 const std::string &address,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500747 std::shared_ptr<AsyncResp> asyncResp)
748{
749 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
750 if (ec)
751 {
752 messages::internalError(asyncResp->res);
753 }
754 };
755 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
756 // does not have assosiated gateway property
757 crow::connections::systemBus->async_method_call(
758 std::move(createIpHandler), "xyz.openbmc_project.Network",
759 "/xyz/openbmc_project/network/" + ifaceId,
760 "xyz.openbmc_project.Network.IP.Create", "IP",
761 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
762 "");
763}
764
manojkiraneda2a133282019-02-19 13:09:43 +0530765using GetAllPropertiesType =
766 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
767
768inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
769{
770 auto getConfig = [asyncResp](const boost::system::error_code error_code,
771 const GetAllPropertiesType &dbus_data) {
772 if (error_code)
773 {
774 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
775 messages::internalError(asyncResp->res);
776 return;
777 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500778 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530779 for (const auto &property : dbus_data)
780 {
781 auto value =
782 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
783
784 if (value == nullptr)
785 {
786 continue;
787 }
788 if (property.first == "DNSEnabled")
789 {
790 DHCPConfigTypeJson["UseDNSServers"] = *value;
791 }
792 else if (property.first == "HostNameEnabled")
793 {
794 DHCPConfigTypeJson["UseDomainName"] = *value;
795 }
796 else if (property.first == "NTPEnabled")
797 {
798 DHCPConfigTypeJson["UseNTPServers"] = *value;
799 }
800 }
801 };
802 crow::connections::systemBus->async_method_call(
803 std::move(getConfig), "xyz.openbmc_project.Network",
804 "/xyz/openbmc_project/network/config/dhcp",
805 "org.freedesktop.DBus.Properties", "GetAll",
806 "xyz.openbmc_project.Network.DHCPConfiguration");
807}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808
Ed Tanous4a0cb852018-10-15 07:55:04 -0700809/**
810 * Function that retrieves all properties for given Ethernet Interface
811 * Object
812 * from EntityManager Network Manager
813 * @param ethiface_id a eth interface id to query on DBus
814 * @param callback a function that shall be called to convert Dbus output
815 * into JSON
816 */
817template <typename CallbackFunc>
818void getEthernetIfaceData(const std::string &ethiface_id,
819 CallbackFunc &&callback)
820{
821 crow::connections::systemBus->async_method_call(
822 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
823 const boost::system::error_code error_code,
824 const GetManagedObjects &resp) {
825 EthernetInterfaceData ethData{};
826 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500827 boost::container::flat_set<IPv6AddressData> ipv6Data;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700828
829 if (error_code)
830 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700831 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700832 return;
833 }
834
Ed Tanous4c9afe42019-05-03 16:59:57 -0700835 bool found =
836 extractEthernetInterfaceData(ethiface_id, resp, ethData);
837 if (!found)
838 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700839 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700840 return;
841 }
842
Johnathan Mantey01784822019-06-18 12:44:21 -0700843 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700844 // Fix global GW
845 for (IPv4AddressData &ipv4 : ipv4Data)
846 {
Ravi Tejac6191412019-07-30 00:53:50 -0500847 if (((ipv4.linktype == LinkType::Global) &&
848 (ipv4.gateway == "0.0.0.0")) ||
849 (ipv4.origin == "DHCP"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700851 ipv4.gateway = ethData.default_gateway;
852 }
853 }
854
Johnathan Mantey01784822019-06-18 12:44:21 -0700855 extractIPV6Data(ethiface_id, resp, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700856 // Finally make a callback with usefull data
Johnathan Mantey01784822019-06-18 12:44:21 -0700857 callback(true, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700858 },
859 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
860 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
861};
862
863/**
864 * Function that retrieves all Ethernet Interfaces available through Network
865 * Manager
866 * @param callback a function that shall be called to convert Dbus output
867 * into JSON.
868 */
869template <typename CallbackFunc>
870void getEthernetIfaceList(CallbackFunc &&callback)
871{
872 crow::connections::systemBus->async_method_call(
873 [callback{std::move(callback)}](
874 const boost::system::error_code error_code,
875 GetManagedObjects &resp) {
876 // Callback requires vector<string> to retrieve all available
877 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700878 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700879 iface_list.reserve(resp.size());
880 if (error_code)
881 {
882 callback(false, iface_list);
883 return;
884 }
885
886 // Iterate over all retrieved ObjectPaths.
887 for (const auto &objpath : resp)
888 {
889 // And all interfaces available for certain ObjectPath.
890 for (const auto &interface : objpath.second)
891 {
892 // If interface is
893 // xyz.openbmc_project.Network.EthernetInterface, this is
894 // what we're looking for.
895 if (interface.first ==
896 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700898 // Cut out everyting until last "/", ...
899 const std::string &iface_id = objpath.first.str;
900 std::size_t last_pos = iface_id.rfind("/");
901 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700902 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700903 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700904 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 }
906 }
907 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700908 }
909 // Finally make a callback with useful data
910 callback(true, iface_list);
911 },
912 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
913 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100914};
915
916/**
917 * EthernetCollection derived class for delivering Ethernet Collection Schema
918 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700919class EthernetCollection : public Node
920{
921 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700922 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700923 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700924 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700925 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926 entityPrivileges = {
927 {boost::beast::http::verb::get, {{"Login"}}},
928 {boost::beast::http::verb::head, {{"Login"}}},
929 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
930 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
931 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
932 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
933 }
934
935 private:
936 /**
937 * Functions triggers appropriate requests on DBus
938 */
939 void doGet(crow::Response &res, const crow::Request &req,
940 const std::vector<std::string> &params) override
941 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800942 res.jsonValue["@odata.type"] =
943 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
944 res.jsonValue["@odata.context"] =
945 "/redfish/v1/"
946 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
947 res.jsonValue["@odata.id"] =
948 "/redfish/v1/Managers/bmc/EthernetInterfaces";
949 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
950 res.jsonValue["Description"] =
951 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700952 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700953 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700954 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700955 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700956 [asyncResp](
957 const bool &success,
958 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700959 if (!success)
960 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700961 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700962 return;
963 }
964
Ed Tanous4c9afe42019-05-03 16:59:57 -0700965 nlohmann::json &iface_array =
966 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700967 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500968 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700969 for (const std::string &iface_item : iface_list)
970 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500971 std::size_t found = iface_item.find(tag);
972 if (found == std::string::npos)
973 {
974 iface_array.push_back(
975 {{"@odata.id",
976 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
977 iface_item}});
978 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700979 }
980
Ed Tanous4c9afe42019-05-03 16:59:57 -0700981 asyncResp->res.jsonValue["Members@odata.count"] =
982 iface_array.size();
983 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700984 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700985 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700986 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100987};
988
989/**
990 * EthernetInterface derived class for delivering Ethernet Schema
991 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700992class EthernetInterface : public Node
993{
994 public:
995 /*
996 * Default Constructor
997 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700998 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001000 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001001 std::string())
1002 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001003 entityPrivileges = {
1004 {boost::beast::http::verb::get, {{"Login"}}},
1005 {boost::beast::http::verb::head, {{"Login"}}},
1006 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1007 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1008 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1009 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001010 }
1011
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001013 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001014 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001015 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001016 asyncResp->res.jsonValue["HostName"] = hostname;
1017 crow::connections::systemBus->async_method_call(
1018 [asyncResp](const boost::system::error_code ec) {
1019 if (ec)
1020 {
1021 messages::internalError(asyncResp->res);
1022 }
1023 },
1024 "xyz.openbmc_project.Network",
1025 "/xyz/openbmc_project/network/config",
1026 "org.freedesktop.DBus.Properties", "Set",
1027 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001028 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 }
1030
Ratan Guptad5776652019-03-03 08:47:22 +05301031 void handleMACAddressPatch(const std::string &ifaceId,
1032 const std::string &macAddress,
1033 const std::shared_ptr<AsyncResp> &asyncResp)
1034 {
1035 crow::connections::systemBus->async_method_call(
1036 [asyncResp, macAddress](const boost::system::error_code ec) {
1037 if (ec)
1038 {
1039 messages::internalError(asyncResp->res);
1040 return;
1041 }
Ratan Guptad5776652019-03-03 08:47:22 +05301042 },
1043 "xyz.openbmc_project.Network",
1044 "/xyz/openbmc_project/network/" + ifaceId,
1045 "org.freedesktop.DBus.Properties", "Set",
1046 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1047 std::variant<std::string>(macAddress));
1048 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001049
Jennifer Leeda131a92019-04-24 15:13:55 -07001050 void setDHCPEnabled(const std::string &ifaceId,
1051 const std::string &propertyName, const bool &value,
1052 const std::shared_ptr<AsyncResp> asyncResp)
1053 {
1054 crow::connections::systemBus->async_method_call(
1055 [asyncResp](const boost::system::error_code ec) {
1056 if (ec)
1057 {
1058 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1059 messages::internalError(asyncResp->res);
1060 return;
1061 }
1062 },
1063 "xyz.openbmc_project.Network",
1064 "/xyz/openbmc_project/network/" + ifaceId,
1065 "org.freedesktop.DBus.Properties", "Set",
1066 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1067 std::variant<bool>{value});
1068 }
1069 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1070 const std::shared_ptr<AsyncResp> asyncResp)
1071 {
1072 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1073 crow::connections::systemBus->async_method_call(
1074 [asyncResp](const boost::system::error_code ec) {
1075 if (ec)
1076 {
1077 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1078 messages::internalError(asyncResp->res);
1079 return;
1080 }
1081 },
1082 "xyz.openbmc_project.Network",
1083 "/xyz/openbmc_project/network/config/dhcp",
1084 "org.freedesktop.DBus.Properties", "Set",
1085 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1086 std::variant<bool>{value});
1087 }
Ratan Guptad5776652019-03-03 08:47:22 +05301088
Jennifer Leeda131a92019-04-24 15:13:55 -07001089 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1090 const std::shared_ptr<AsyncResp> asyncResp)
1091 {
1092 std::optional<bool> dhcpEnabled;
1093 std::optional<bool> useDNSServers;
1094 std::optional<bool> useDomainName;
1095 std::optional<bool> useNTPServers;
1096
1097 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1098 dhcpEnabled, "UseDNSServers", useDNSServers,
1099 "UseDomainName", useDomainName,
1100 "UseNTPServers", useNTPServers))
1101 {
1102 return;
1103 }
1104
1105 if (dhcpEnabled)
1106 {
1107 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1108 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1109 }
1110
1111 if (useDNSServers)
1112 {
1113 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1114 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1115 }
1116
1117 if (useDomainName)
1118 {
1119 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1120 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1121 }
1122
1123 if (useNTPServers)
1124 {
1125 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1126 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1127 }
1128 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001129
1130 boost::container::flat_set<IPv4AddressData>::const_iterator
1131 GetNextStaticIPEntry(
1132 boost::container::flat_set<IPv4AddressData>::const_iterator head,
1133 boost::container::flat_set<IPv4AddressData>::const_iterator end)
1134 {
1135 for (; head != end; head++)
1136 {
1137 if (head->origin == "Static")
1138 {
1139 return head;
1140 }
1141 }
1142 return end;
1143 }
1144
1145 boost::container::flat_set<IPv6AddressData>::const_iterator
1146 GetNextStaticIPEntry(
1147 boost::container::flat_set<IPv6AddressData>::const_iterator head,
1148 boost::container::flat_set<IPv6AddressData>::const_iterator end)
1149 {
1150 for (; head != end; head++)
1151 {
1152 if (head->origin == "Static")
1153 {
1154 return head;
1155 }
1156 }
1157 return end;
1158 }
1159
Ravi Tejad1d50812019-06-23 16:20:27 -05001160 void handleIPv4StaticPatch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301161 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001162 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001163 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001164 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001165 if ((!input.is_array()) || input.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301166 {
1167 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Ravi Tejad1d50812019-06-23 16:20:27 -05001168 "IPv4StaticAddresses");
Ratan Guptaf476acb2019-03-02 16:46:57 +05301169 return;
1170 }
1171
Johnathan Mantey01784822019-06-18 12:44:21 -07001172 int entryIdx = 1;
1173 // Find the first static IP address currently active on the NIC and
1174 // match it to the first JSON element in the IPv4StaticAddresses array.
1175 // Match each subsequent JSON element to the next static IP programmed
1176 // into the NIC.
1177 boost::container::flat_set<IPv4AddressData>::const_iterator NICIPentry =
1178 GetNextStaticIPEntry(ipv4Data.cbegin(), ipv4Data.cend());
1179
Ed Tanous537174c2018-12-10 15:09:31 -08001180 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001181 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001182 std::string pathString =
Ravi Tejad1d50812019-06-23 16:20:27 -05001183 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001184
Johnathan Mantey01784822019-06-18 12:44:21 -07001185 if (!thisJson.is_null() && !thisJson.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301186 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001187 std::optional<std::string> address;
1188 std::optional<std::string> subnetMask;
1189 std::optional<std::string> gateway;
1190
1191 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1192 address, "SubnetMask", subnetMask,
1193 "Gateway", gateway))
Ratan Guptaf476acb2019-03-02 16:46:57 +05301194 {
1195 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001196 asyncResp->res, thisJson.dump(), pathString);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301197 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301198 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301199
Johnathan Mantey01784822019-06-18 12:44:21 -07001200 // Find the address/subnet/gateway values. Any values that are
1201 // not explicitly provided are assumed to be unmodified from the
1202 // current state of the interface. Merge existing state into the
1203 // current request.
1204 const std::string *addr;
1205 const std::string *gw;
1206 uint8_t prefixLength = 0;
1207 bool errorInEntry = false;
1208 if (address)
Ratan Gupta9474b372019-03-01 15:13:37 +05301209 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001210 if (ipv4VerifyIpAndGetBitcount(*address))
1211 {
1212 addr = &(*address);
1213 }
1214 else
1215 {
1216 messages::propertyValueFormatError(
1217 asyncResp->res, *address, pathString + "/Address");
1218 errorInEntry = true;
1219 }
1220 }
1221 else if (NICIPentry != ipv4Data.cend())
1222 {
1223 addr = &(NICIPentry->address);
Ratan Gupta9474b372019-03-01 15:13:37 +05301224 }
1225 else
1226 {
1227 messages::propertyMissing(asyncResp->res,
1228 pathString + "/Address");
Johnathan Mantey01784822019-06-18 12:44:21 -07001229 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001230 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301231
1232 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001233 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001234 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
1235 {
1236 messages::propertyValueFormatError(
1237 asyncResp->res, *subnetMask,
1238 pathString + "/SubnetMask");
1239 errorInEntry = true;
1240 }
1241 }
1242 else if (NICIPentry != ipv4Data.cend())
1243 {
1244 if (!ipv4VerifyIpAndGetBitcount(NICIPentry->netmask,
1245 &prefixLength))
1246 {
1247 messages::propertyValueFormatError(
1248 asyncResp->res, NICIPentry->netmask,
1249 pathString + "/SubnetMask");
1250 errorInEntry = true;
1251 }
1252 }
1253 else
1254 {
1255 messages::propertyMissing(asyncResp->res,
1256 pathString + "/SubnetMask");
1257 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001258 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301259
Ratan Guptaf476acb2019-03-02 16:46:57 +05301260 if (gateway)
1261 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001262 if (ipv4VerifyIpAndGetBitcount(*gateway))
1263 {
1264 gw = &(*gateway);
1265 }
1266 else
1267 {
1268 messages::propertyValueFormatError(
1269 asyncResp->res, *gateway, pathString + "/Gateway");
1270 errorInEntry = true;
1271 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301272 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001273 else if (NICIPentry != ipv4Data.cend())
1274 {
1275 gw = &NICIPentry->gateway;
1276 }
1277 else
Ed Tanous4a0cb852018-10-15 07:55:04 -07001278 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001279 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001280 pathString + "/Gateway");
Johnathan Mantey01784822019-06-18 12:44:21 -07001281 errorInEntry = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001282 }
1283
Johnathan Mantey01784822019-06-18 12:44:21 -07001284 if (errorInEntry)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001285 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001286 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001287 }
1288
Johnathan Mantey01784822019-06-18 12:44:21 -07001289 if (NICIPentry != ipv4Data.cend())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001290 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001291 deleteAndCreateIPv4(ifaceId, NICIPentry->id, prefixLength,
1292 *gw, *addr, asyncResp);
1293 NICIPentry =
1294 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
Ed Tanous4a0cb852018-10-15 07:55:04 -07001295 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001296 else
1297 {
1298 createIPv4(ifaceId, entryIdx, prefixLength, *gateway,
1299 *address, asyncResp);
1300 }
1301 entryIdx++;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001302 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001303 else
1304 {
1305 if (NICIPentry == ipv4Data.cend())
1306 {
1307 // Requesting a DELETE/DO NOT MODIFY action for an item
1308 // that isn't present on the eth(n) interface. Input JSON is
1309 // in error, so bail out.
1310 if (thisJson.is_null())
1311 {
1312 messages::resourceCannotBeDeleted(asyncResp->res);
1313 return;
1314 }
1315 else
1316 {
1317 messages::propertyValueFormatError(
1318 asyncResp->res, thisJson.dump(), pathString);
1319 return;
1320 }
1321 }
1322
1323 if (thisJson.is_null())
1324 {
1325 deleteIPv4(ifaceId, NICIPentry->id, asyncResp);
1326 }
1327 if (NICIPentry != ipv4Data.cend())
1328 {
1329 NICIPentry =
1330 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
1331 }
1332 entryIdx++;
1333 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001334 }
1335 }
1336
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001337 void handleStaticNameServersPatch(
1338 const std::string &ifaceId,
1339 const std::vector<std::string> &updatedStaticNameServers,
1340 const std::shared_ptr<AsyncResp> &asyncResp)
1341 {
1342 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001343 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001344 if (ec)
1345 {
1346 messages::internalError(asyncResp->res);
1347 return;
1348 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001349 },
1350 "xyz.openbmc_project.Network",
1351 "/xyz/openbmc_project/network/" + ifaceId,
1352 "org.freedesktop.DBus.Properties", "Set",
1353 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1354 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1355 }
1356
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001357 void handleIPv6StaticAddressesPatch(
1358 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001359 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001360 const std::shared_ptr<AsyncResp> asyncResp)
1361 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001362 if (!input.is_array() || input.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001363 {
1364 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1365 "IPv6StaticAddresses");
1366 return;
1367 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001368 int entryIdx = 1;
1369 boost::container::flat_set<IPv6AddressData>::const_iterator NICIPentry =
1370 GetNextStaticIPEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001371 for (nlohmann::json &thisJson : input)
1372 {
1373 std::string pathString =
1374 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1375
Johnathan Mantey01784822019-06-18 12:44:21 -07001376 if (!thisJson.is_null() && !thisJson.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001377 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001378 std::optional<std::string> address;
1379 std::optional<uint8_t> prefixLength;
1380
1381 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1382 address, "PrefixLength", prefixLength))
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001383 {
1384 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001385 asyncResp->res, thisJson.dump(), pathString);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001386 return;
1387 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001388
Johnathan Mantey01784822019-06-18 12:44:21 -07001389 const std::string *addr;
1390 uint8_t prefix;
1391
1392 // Find the address and prefixLength values. Any values that are
1393 // not explicitly provided are assumed to be unmodified from the
1394 // current state of the interface. Merge existing state into the
1395 // current request.
1396 if (address)
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001397 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001398 addr = &(*address);
1399 }
1400 else if (NICIPentry != ipv6Data.end())
1401 {
1402 addr = &(NICIPentry->address);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001403 }
1404 else
1405 {
1406 messages::propertyMissing(asyncResp->res,
1407 pathString + "/Address");
1408 return;
1409 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001410
1411 if (prefixLength)
1412 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001413 prefix = *prefixLength;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001414 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001415 else if (NICIPentry != ipv6Data.end())
1416 {
1417 prefix = NICIPentry->prefixLength;
1418 }
1419 else
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001420 {
1421 messages::propertyMissing(asyncResp->res,
1422 pathString + "/PrefixLength");
Johnathan Mantey01784822019-06-18 12:44:21 -07001423 return;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001424 }
1425
Johnathan Mantey01784822019-06-18 12:44:21 -07001426 if (NICIPentry != ipv6Data.end())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001427 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001428 deleteAndCreateIPv6(ifaceId, NICIPentry->id, prefix, *addr,
1429 asyncResp);
1430 NICIPentry =
1431 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1432 }
1433 else
1434 {
1435 createIPv6(ifaceId, *prefixLength, *addr, asyncResp);
1436 }
1437 entryIdx++;
1438 }
1439 else
1440 {
1441 if (NICIPentry == ipv6Data.end())
1442 {
1443 // Requesting a DELETE/DO NOT MODIFY action for an item
1444 // that isn't present on the eth(n) interface. Input JSON is
1445 // in error, so bail out.
1446 if (thisJson.is_null())
1447 {
1448 messages::resourceCannotBeDeleted(asyncResp->res);
1449 return;
1450 }
1451 else
1452 {
1453 messages::propertyValueFormatError(
1454 asyncResp->res, thisJson.dump(), pathString);
1455 return;
1456 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001457 }
1458
Johnathan Mantey01784822019-06-18 12:44:21 -07001459 if (thisJson.is_null())
1460 {
1461 deleteIPv6(ifaceId, NICIPentry->id, asyncResp);
1462 }
1463 if (NICIPentry != ipv6Data.cend())
1464 {
1465 NICIPentry =
1466 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1467 }
1468 entryIdx++;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001469 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001470 }
1471 }
1472
Ed Tanous0f74e642018-11-12 15:17:05 -08001473 void parseInterfaceData(
1474 nlohmann::json &json_response, const std::string &iface_id,
1475 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001476 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001477 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001478 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001479 json_response["Id"] = iface_id;
1480 json_response["@odata.id"] =
1481 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001482 json_response["InterfaceEnabled"] = true;
1483 if (ethData.speed == 0)
1484 {
1485 json_response["LinkStatus"] = "NoLink";
1486 json_response["Status"] = {
1487 {"Health", "OK"},
1488 {"State", "Disabled"},
1489 };
1490 }
1491 else
1492 {
1493 json_response["LinkStatus"] = "LinkUp";
1494 json_response["Status"] = {
1495 {"Health", "OK"},
1496 {"State", "Enabled"},
1497 };
1498 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001499 json_response["SpeedMbps"] = ethData.speed;
1500 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001501 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301502
Ed Tanous4a0cb852018-10-15 07:55:04 -07001503 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001504 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001505 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001506 if (!ethData.domainnames.empty())
1507 {
1508 json_response["FQDN"] =
1509 ethData.hostname + "." + ethData.domainnames[0];
1510 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001511 }
1512
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001513 json_response["VLANs"] = {
1514 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1515 iface_id + "/VLANs"}};
1516
Ed Tanous029573d2019-02-01 10:57:49 -08001517 json_response["NameServers"] = ethData.nameservers;
Manojkiran Eda95f86462019-08-07 15:07:54 +05301518
1519 if (!ethData.DHCPEnabled)
1520 {
1521 json_response["StaticNameServers"] = ethData.nameservers;
1522 }
1523 else
1524 {
Manojkiran Edaf1a3cae2019-08-27 14:23:10 +05301525 json_response["StaticNameServers"] = nlohmann::json::array();
Manojkiran Eda95f86462019-08-07 15:07:54 +05301526 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527
Ravi Tejad1d50812019-06-23 16:20:27 -05001528 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001529 nlohmann::json &ipv4_static_array =
1530 json_response["IPv4StaticAddresses"];
Ravi Tejad1d50812019-06-23 16:20:27 -05001531 ipv4_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001532 ipv4_static_array = nlohmann::json::array();
Ravi Tejad1d50812019-06-23 16:20:27 -05001533 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001534 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001535
1536 std::string gatewayStr = ipv4_config.gateway;
1537 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001538 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001539 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001540 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001541
1542 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1543 {"SubnetMask", ipv4_config.netmask},
1544 {"Address", ipv4_config.address},
1545 {"Gateway", gatewayStr}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001546 if (ipv4_config.origin == "Static")
Ravi Tejad1d50812019-06-23 16:20:27 -05001547 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001548 ipv4_static_array.push_back(
1549 {{"AddressOrigin", ipv4_config.origin},
1550 {"SubnetMask", ipv4_config.netmask},
1551 {"Address", ipv4_config.address},
1552 {"Gateway", gatewayStr}});
Ravi Tejad1d50812019-06-23 16:20:27 -05001553 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001554 }
1555
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001556 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001557
1558 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001559 nlohmann::json &ipv6_static_array =
1560 json_response["IPv6StaticAddresses"];
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001561 ipv6_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001562 ipv6_static_array = nlohmann::json::array();
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001563 for (auto &ipv6_config : ipv6Data)
1564 {
1565 ipv6_array.push_back({{"Address", ipv6_config.address},
1566 {"PrefixLength", ipv6_config.prefixLength},
1567 {"AddressOrigin", ipv6_config.origin}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001568 if (ipv6_config.origin == "Static")
1569 {
1570 ipv6_static_array.push_back(
1571 {{"Address", ipv6_config.address},
1572 {"PrefixLength", ipv6_config.prefixLength},
1573 {"AddressOrigin", ipv6_config.origin}});
1574 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001575 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001576 }
1577
1578 /**
1579 * Functions triggers appropriate requests on DBus
1580 */
1581 void doGet(crow::Response &res, const crow::Request &req,
1582 const std::vector<std::string> &params) override
1583 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001584 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585 if (params.size() != 1)
1586 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001587 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588 return;
1589 }
1590
Ed Tanous4a0cb852018-10-15 07:55:04 -07001591 getEthernetIfaceData(
1592 params[0],
1593 [this, asyncResp, iface_id{std::string(params[0])}](
1594 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001595 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001596 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001597 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001598 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001599 // TODO(Pawel)consider distinguish between non existing
1600 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001601 messages::resourceNotFound(asyncResp->res,
1602 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001603 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001604 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001605
1606 // because this has no dependence on the interface at this
1607 // point, it needs to be done after we know the interface
1608 // exists, not before.
1609 getDHCPConfigData(asyncResp);
1610
Ed Tanous0f74e642018-11-12 15:17:05 -08001611 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001612 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001613 asyncResp->res.jsonValue["@odata.context"] =
Johnathan Mantey01784822019-06-18 12:44:21 -07001614 "/redfish/v1/"
1615 "$metadata#EthernetInterface.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001616 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1617 asyncResp->res.jsonValue["Description"] =
1618 "Management Network Interface";
1619
1620 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Johnathan Mantey01784822019-06-18 12:44:21 -07001621 ipv4Data, ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001622 });
1623 }
1624
1625 void doPatch(crow::Response &res, const crow::Request &req,
1626 const std::vector<std::string> &params) override
1627 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001628 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001629 if (params.size() != 1)
1630 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001631 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001632 return;
1633 }
1634
Ed Tanous4a0cb852018-10-15 07:55:04 -07001635 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001636
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001637 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301638 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001639 std::optional<std::string> ipv6DefaultGateway;
Ravi Tejad1d50812019-06-23 16:20:27 -05001640 std::optional<nlohmann::json> ipv4StaticAddresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001641 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001642 std::optional<std::vector<std::string>> staticNameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001643 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001644
Johnathan Mantey01784822019-06-18 12:44:21 -07001645 if (!json_util::readJson(req, res, "HostName", hostname,
1646 "IPv4StaticAddresses", ipv4StaticAddresses,
1647 "MACAddress", macAddress, "StaticNameServers",
1648 staticNameServers, "IPv6DefaultGateway",
1649 ipv6DefaultGateway, "IPv6StaticAddresses",
1650 ipv6StaticAddresses, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 {
1652 return;
1653 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301654
Jennifer Leeda131a92019-04-24 15:13:55 -07001655 if (dhcpv4)
1656 {
1657 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1658 }
1659
Johnathan Mantey01784822019-06-18 12:44:21 -07001660 // Get single eth interface data, and call the below callback for
1661 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001662 getEthernetIfaceData(
1663 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001664 [this, asyncResp, iface_id, hostname = std::move(hostname),
1665 macAddress = std::move(macAddress),
Ravi Tejad1d50812019-06-23 16:20:27 -05001666 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001667 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001668 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
Johnathan Mantey01784822019-06-18 12:44:21 -07001669 staticNameServers = std::move(staticNameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001670 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001671 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001672 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 if (!success)
1674 {
1675 // ... otherwise return error
1676 // TODO(Pawel)consider distinguish between non existing
1677 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001678 messages::resourceNotFound(asyncResp->res,
1679 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001680 return;
1681 }
1682
Ed Tanous0627a2c2018-11-29 17:09:23 -08001683 if (hostname)
1684 {
1685 handleHostnamePatch(*hostname, asyncResp);
1686 }
1687
Ratan Guptad5776652019-03-03 08:47:22 +05301688 if (macAddress)
1689 {
1690 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1691 }
1692
Ravi Tejad1d50812019-06-23 16:20:27 -05001693 if (ipv4StaticAddresses)
1694 {
Ed Tanous537174c2018-12-10 15:09:31 -08001695 // TODO(ed) for some reason the capture of ipv4Addresses
Johnathan Mantey01784822019-06-18 12:44:21 -07001696 // above is returning a const value, not a non-const
1697 // value. This doesn't really work for us, as we need to
1698 // be able to efficiently move out the intermedia
1699 // nlohmann::json objects. This makes a copy of the
1700 // structure, and operates on that, but could be done
1701 // more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001702 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
Johnathan Mantey01784822019-06-18 12:44:21 -07001703 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001704 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001705 }
1706
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001707 if (staticNameServers)
1708 {
1709 handleStaticNameServersPatch(iface_id, *staticNameServers,
1710 asyncResp);
1711 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001712
1713 if (ipv6DefaultGateway)
1714 {
1715 messages::propertyNotWritable(asyncResp->res,
1716 "IPv6DefaultGateway");
1717 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001718
1719 if (ipv6StaticAddresses)
1720 {
1721 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1722 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
Johnathan Mantey01784822019-06-18 12:44:21 -07001723 ipv6Data, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001724 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001725 });
1726 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001727};
1728
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001729/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001730 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1731 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001732 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001733class VlanNetworkInterface : public Node
1734{
1735 public:
1736 /*
1737 * Default Constructor
1738 */
1739 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001741 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001742 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001743 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001744 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 entityPrivileges = {
1746 {boost::beast::http::verb::get, {{"Login"}}},
1747 {boost::beast::http::verb::head, {{"Login"}}},
1748 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1749 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1750 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1751 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001752 }
1753
Ed Tanous1abe55e2018-09-05 08:30:59 -07001754 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001755 void parseInterfaceData(
1756 nlohmann::json &json_response, const std::string &parent_iface_id,
1757 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001758 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001759 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001760 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001761 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001762 json_response["Id"] = iface_id;
1763 json_response["@odata.id"] =
1764 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1765 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001766
Ed Tanous4a0cb852018-10-15 07:55:04 -07001767 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001768 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001769 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001770 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001771 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001772 }
1773
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001774 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775 {
1776 if (!boost::starts_with(iface, parent + "_"))
1777 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001778 return false;
1779 }
1780 else
1781 {
1782 return true;
1783 }
1784 }
1785
1786 /**
1787 * Functions triggers appropriate requests on DBus
1788 */
1789 void doGet(crow::Response &res, const crow::Request &req,
1790 const std::vector<std::string> &params) override
1791 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001792 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1793 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001794 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1795 // Check if there is required param, truly entering this shall be
1796 // impossible.
1797 if (params.size() != 2)
1798 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001799 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001800 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001801 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001803
Ed Tanous4a0cb852018-10-15 07:55:04 -07001804 const std::string &parent_iface_id = params[0];
1805 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001806 res.jsonValue["@odata.type"] =
1807 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1808 res.jsonValue["@odata.context"] =
Johnathan Mantey01784822019-06-18 12:44:21 -07001809 "/redfish/v1/"
1810 "$metadata#VLanNetworkInterface.VLanNetworkInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001811 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001812
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001813 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 {
1815 return;
1816 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001817
Johnathan Mantey01784822019-06-18 12:44:21 -07001818 // Get single eth interface data, and call the below callback for
1819 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001820 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001821 params[1],
1822 [this, asyncResp, parent_iface_id{std::string(params[0])},
1823 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001824 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001825 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001826 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001827 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001828 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001829 parseInterfaceData(asyncResp->res.jsonValue,
1830 parent_iface_id, iface_id, ethData,
Johnathan Mantey01784822019-06-18 12:44:21 -07001831 ipv4Data, ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001832 }
1833 else
1834 {
1835 // ... otherwise return error
1836 // TODO(Pawel)consider distinguish between non existing
1837 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001838 messages::resourceNotFound(
1839 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001841 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001842 }
1843
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 void doPatch(crow::Response &res, const crow::Request &req,
1845 const std::vector<std::string> &params) override
1846 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001847 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848 if (params.size() != 2)
1849 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001850 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001851 return;
1852 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001853
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 const std::string &parentIfaceId = params[0];
1855 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001856
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001857 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001859 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1860 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 return;
1862 }
1863
Ed Tanous0627a2c2018-11-29 17:09:23 -08001864 bool vlanEnable = false;
1865 uint64_t vlanId = 0;
1866
1867 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1868 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 {
1870 return;
1871 }
1872
Johnathan Mantey01784822019-06-18 12:44:21 -07001873 // Get single eth interface data, and call the below callback for
1874 // JSON preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001875 getEthernetIfaceData(
1876 params[1],
1877 [this, asyncResp, parentIfaceId{std::string(params[0])},
1878 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1879 const bool &success, const EthernetInterfaceData &ethData,
1880 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001881 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001882 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001883 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001884 auto callback =
1885 [asyncResp](const boost::system::error_code ec) {
1886 if (ec)
1887 {
1888 messages::internalError(asyncResp->res);
1889 }
1890 };
1891
1892 if (vlanEnable == true)
1893 {
1894 crow::connections::systemBus->async_method_call(
1895 std::move(callback), "xyz.openbmc_project.Network",
1896 "/xyz/openbmc_project/network/" + ifaceId,
1897 "org.freedesktop.DBus.Properties", "Set",
1898 "xyz.openbmc_project.Network.VLAN", "Id",
1899 std::variant<uint32_t>(vlanId));
1900 }
1901 else
1902 {
1903 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1904 "vlan interface";
1905 crow::connections::systemBus->async_method_call(
1906 std::move(callback), "xyz.openbmc_project.Network",
1907 std::string("/xyz/openbmc_project/network/") +
1908 ifaceId,
1909 "xyz.openbmc_project.Object.Delete", "Delete");
1910 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001911 }
1912 else
1913 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001914 // TODO(Pawel)consider distinguish between non existing
1915 // object, and other errors
1916 messages::resourceNotFound(
1917 asyncResp->res, "VLAN Network Interface", ifaceId);
1918 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001919 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001920 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 }
1922
1923 void doDelete(crow::Response &res, const crow::Request &req,
1924 const std::vector<std::string> &params) override
1925 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001926 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001927 if (params.size() != 2)
1928 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001929 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001930 return;
1931 }
1932
1933 const std::string &parentIfaceId = params[0];
1934 const std::string &ifaceId = params[1];
1935
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001936 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001937 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001938 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1939 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001940 return;
1941 }
1942
Johnathan Mantey01784822019-06-18 12:44:21 -07001943 // Get single eth interface data, and call the below callback for
1944 // JSON preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001945 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001946 params[1],
1947 [this, asyncResp, parentIfaceId{std::string(params[0])},
1948 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001949 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001950 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001951 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001952 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001953 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001954 auto callback =
1955 [asyncResp](const boost::system::error_code ec) {
1956 if (ec)
1957 {
1958 messages::internalError(asyncResp->res);
1959 }
1960 };
1961 crow::connections::systemBus->async_method_call(
1962 std::move(callback), "xyz.openbmc_project.Network",
1963 std::string("/xyz/openbmc_project/network/") + ifaceId,
1964 "xyz.openbmc_project.Object.Delete", "Delete");
1965 }
1966 else
1967 {
1968 // ... otherwise return error
1969 // TODO(Pawel)consider distinguish between non existing
1970 // object, and other errors
1971 messages::resourceNotFound(
1972 asyncResp->res, "VLAN Network Interface", ifaceId);
1973 }
1974 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001975 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001976};
1977
1978/**
1979 * VlanNetworkInterfaceCollection derived class for delivering
1980 * VLANNetworkInterface Collection Schema
1981 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001982class VlanNetworkInterfaceCollection : public Node
1983{
1984 public:
1985 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001986 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001987 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1988 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001989 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001990 entityPrivileges = {
1991 {boost::beast::http::verb::get, {{"Login"}}},
1992 {boost::beast::http::verb::head, {{"Login"}}},
1993 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1994 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1995 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1996 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001997 }
1998
Ed Tanous1abe55e2018-09-05 08:30:59 -07001999 private:
2000 /**
2001 * Functions triggers appropriate requests on DBus
2002 */
2003 void doGet(crow::Response &res, const crow::Request &req,
2004 const std::vector<std::string> &params) override
2005 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002006 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002007 if (params.size() != 1)
2008 {
2009 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002010 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002011 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002012 }
2013
Ed Tanous4a0cb852018-10-15 07:55:04 -07002014 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002015
Ed Tanous4a0cb852018-10-15 07:55:04 -07002016 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002017 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002018 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002019 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002020 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002021 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002022 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002023 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002024 messages::internalError(asyncResp->res);
2025 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002026 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002027
2028 if (iface_list.find(rootInterfaceName) == iface_list.end())
2029 {
2030 messages::resourceNotFound(asyncResp->res,
2031 "VLanNetworkInterfaceCollection",
2032 rootInterfaceName);
2033 return;
2034 }
2035
Ed Tanous0f74e642018-11-12 15:17:05 -08002036 asyncResp->res.jsonValue["@odata.type"] =
2037 "#VLanNetworkInterfaceCollection."
2038 "VLanNetworkInterfaceCollection";
2039 asyncResp->res.jsonValue["@odata.context"] =
2040 "/redfish/v1/$metadata"
2041 "#VLanNetworkInterfaceCollection."
2042 "VLanNetworkInterfaceCollection";
2043 asyncResp->res.jsonValue["Name"] =
2044 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002045
Jason M. Billsf12894f2018-10-09 12:45:45 -07002046 nlohmann::json iface_array = nlohmann::json::array();
2047
2048 for (const std::string &iface_item : iface_list)
2049 {
2050 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2051 {
2052 iface_array.push_back(
2053 {{"@odata.id",
2054 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2055 rootInterfaceName + "/VLANs/" + iface_item}});
2056 }
2057 }
2058
Jason M. Billsf12894f2018-10-09 12:45:45 -07002059 asyncResp->res.jsonValue["Members@odata.count"] =
2060 iface_array.size();
2061 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2062 asyncResp->res.jsonValue["@odata.id"] =
2063 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2064 rootInterfaceName + "/VLANs";
2065 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002066 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002067
Ed Tanous1abe55e2018-09-05 08:30:59 -07002068 void doPost(crow::Response &res, const crow::Request &req,
2069 const std::vector<std::string> &params) override
2070 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002071 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002072 if (params.size() != 1)
2073 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002074 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002075 return;
2076 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002077 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002078 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002079 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2080 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002081 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002082 return;
2083 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002084 // Need both vlanId and vlanEnable to service this request
2085 if (!vlanId)
2086 {
2087 messages::propertyMissing(asyncResp->res, "VLANId");
2088 }
2089 if (!vlanEnable)
2090 {
2091 messages::propertyMissing(asyncResp->res, "VLANEnable");
2092 }
2093 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2094 {
2095 return;
2096 }
2097
Ed Tanous4a0cb852018-10-15 07:55:04 -07002098 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002099 auto callback = [asyncResp](const boost::system::error_code ec) {
2100 if (ec)
2101 {
2102 // TODO(ed) make more consistent error messages based on
2103 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002104 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002105 return;
2106 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002107 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002108 };
2109 crow::connections::systemBus->async_method_call(
2110 std::move(callback), "xyz.openbmc_project.Network",
2111 "/xyz/openbmc_project/network",
2112 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002113 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002114 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002115};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002116} // namespace redfish