blob: 3c509af3e877d4b7727a0994445c8c8fd3946b72 [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous1abe55e2018-09-05 08:30:59 -070018#include <boost/container/flat_map.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070019#include <boost/container/flat_set.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020020#include <dbus_singleton.hpp>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020021#include <error_messages.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020022#include <node.hpp>
Ed Tanousa24526d2018-12-10 15:17:59 -080023#include <optional>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020024#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080025#include <variant>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010029
30/**
31 * DBus types primitives for several generic DBus interfaces
32 * TODO(Pawel) consider move this to separate file into boost::dbus
33 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using PropertiesMapType = boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080035 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36 int32_t, uint32_t, int64_t, uint64_t, double>>;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010037
Ed Tanous4a0cb852018-10-15 07:55:04 -070038using GetManagedObjects = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039 sdbusplus::message::object_path,
Ed Tanous4a0cb852018-10-15 07:55:04 -070040 std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070041 std::string,
42 boost::container::flat_map<
Ed Tanous029573d2019-02-01 10:57:49 -080043 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
45 int32_t, uint32_t, int64_t, uint64_t, double,
46 std::vector<std::string>>>>>>>;
Ed Tanous4a0cb852018-10-15 07:55:04 -070047
48enum class LinkType
49{
50 Local,
51 Global
52};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010053
54/**
55 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010056 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070057struct IPv4AddressData
58{
59 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070060 std::string address;
61 std::string domain;
62 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 std::string netmask;
64 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070065 LinkType linktype;
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 bool operator<(const IPv4AddressData &obj) const
68 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070069 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
81 uint8_t prefixLength;
82
83 bool operator<(const IPv6AddressData &obj) const
84 {
85 return id < obj.id;
86 }
87};
88/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010089 * Structure for keeping basic single Ethernet Interface information
90 * available from DBus
91 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070092struct EthernetInterfaceData
93{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t speed;
95 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053096 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070097 std::string hostname;
98 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -050099 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700100 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500101 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -0800102 std::vector<std::string> nameservers;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100103};
104
Ed Tanous4a0cb852018-10-15 07:55:04 -0700105// Helper function that changes bits netmask notation (i.e. /24)
106// into full dot notation
107inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700109 uint32_t value = 0xffffffff << (32 - bits);
110 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
111 std::to_string((value >> 16) & 0xff) + "." +
112 std::to_string((value >> 8) & 0xff) + "." +
113 std::to_string(value & 0xff);
114 return netmask;
115}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100116
Ed Tanous4a0cb852018-10-15 07:55:04 -0700117inline std::string
118 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
119 bool isIPv4)
120{
121 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700123 return "Static";
124 }
125 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
126 {
127 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700129 return "IPv4LinkLocal";
130 }
131 else
132 {
133 return "LinkLocal";
134 }
135 }
136 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
137 {
138 if (isIPv4)
139 {
140 return "DHCP";
141 }
142 else
143 {
144 return "DHCPv6";
145 }
146 }
147 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
148 {
149 return "SLAAC";
150 }
151 return "";
152}
153
154inline std::string
155 translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
156{
157 if (inputOrigin == "Static")
158 {
159 return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
160 }
161 if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
162 {
163 return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
164 }
165 if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
166 {
167 return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
168 }
169 if (inputOrigin == "SLAAC")
170 {
171 return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
172 }
173 return "";
174}
175
Ed Tanous4c9afe42019-05-03 16:59:57 -0700176inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700177 const GetManagedObjects &dbus_data,
178 EthernetInterfaceData &ethData)
179{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700180 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700181 for (const auto &objpath : dbus_data)
182 {
Ed Tanous029573d2019-02-01 10:57:49 -0800183 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700184 {
Ed Tanous029573d2019-02-01 10:57:49 -0800185 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700187 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700188 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700190 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700192 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700194 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800195 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700196 if (mac != nullptr)
197 {
198 ethData.mac_address = *mac;
199 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700201 }
202 }
203 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
204 {
205 for (const auto &propertyPair : ifacePair.second)
206 {
207 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700208 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800209 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800210 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700211 if (id != nullptr)
212 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500213 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700214 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700216 }
217 }
218 else if (ifacePair.first ==
219 "xyz.openbmc_project.Network.EthernetInterface")
220 {
221 for (const auto &propertyPair : ifacePair.second)
222 {
223 if (propertyPair.first == "AutoNeg")
224 {
225 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800226 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700227 if (auto_neg != nullptr)
228 {
229 ethData.auto_neg = *auto_neg;
230 }
231 }
232 else if (propertyPair.first == "Speed")
233 {
234 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800235 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700236 if (speed != nullptr)
237 {
238 ethData.speed = *speed;
239 }
240 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500241 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700242 {
Ed Tanous029573d2019-02-01 10:57:49 -0800243 const std::vector<std::string> *nameservers =
244 sdbusplus::message::variant_ns::get_if<
245 std::vector<std::string>>(
246 &propertyPair.second);
247 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700248 {
Ed Tanous029573d2019-02-01 10:57:49 -0800249 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700250 }
251 }
manojkiraneda2a133282019-02-19 13:09:43 +0530252 else if (propertyPair.first == "DHCPEnabled")
253 {
254 const bool *DHCPEnabled =
255 std::get_if<bool>(&propertyPair.second);
256 if (DHCPEnabled != nullptr)
257 {
258 ethData.DHCPEnabled = *DHCPEnabled;
259 }
260 }
Ed Tanous029573d2019-02-01 10:57:49 -0800261 }
262 }
263 }
264 // System configuration shows up in the global namespace, so no need
265 // to check eth number
266 if (ifacePair.first ==
267 "xyz.openbmc_project.Network.SystemConfiguration")
268 {
269 for (const auto &propertyPair : ifacePair.second)
270 {
271 if (propertyPair.first == "HostName")
272 {
273 const std::string *hostname =
274 sdbusplus::message::variant_ns::get_if<std::string>(
275 &propertyPair.second);
276 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700277 {
Ed Tanous029573d2019-02-01 10:57:49 -0800278 ethData.hostname = *hostname;
279 }
280 }
281 else if (propertyPair.first == "DefaultGateway")
282 {
283 const std::string *defaultGateway =
284 sdbusplus::message::variant_ns::get_if<std::string>(
285 &propertyPair.second);
286 if (defaultGateway != nullptr)
287 {
288 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700289 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500291 else if (propertyPair.first == "DefaultGateway6")
292 {
293 const std::string *defaultGateway6 =
294 sdbusplus::message::variant_ns::get_if<std::string>(
295 &propertyPair.second);
296 if (defaultGateway6 != nullptr)
297 {
298 ethData.ipv6_default_gateway = *defaultGateway6;
299 }
300 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301 }
302 }
303 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700304 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700305 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700306}
307
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500308// Helper function that extracts data for single ethernet ipv6 address
309inline void extractIPV6Data(
310 const std::string &ethiface_id, const GetManagedObjects &dbus_data,
311 boost::container::flat_set<IPv6AddressData> &ipv6_config,
312 boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
313{
314 const std::string ipv6PathStart =
315 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
316
317 // Since there might be several IPv6 configurations aligned with
318 // single ethernet interface, loop over all of them
319 for (const auto &objpath : dbus_data)
320 {
321 // Check if proper pattern for object path appears
322 if (boost::starts_with(objpath.first.str, ipv6PathStart))
323 {
324 for (auto &interface : objpath.second)
325 {
326 if (interface.first == "xyz.openbmc_project.Network.IP")
327 {
328 // Instance IPv6AddressData structure, and set as
329 // appropriate
330 std::pair<
331 boost::container::flat_set<IPv6AddressData>::iterator,
332 bool>
333 it = ipv6_config.insert(
334 {objpath.first.str.substr(ipv6PathStart.size())});
335 IPv6AddressData &ipv6_address = *it.first;
336 for (auto &property : interface.second)
337 {
338 if (property.first == "Address")
339 {
340 const std::string *address =
341 std::get_if<std::string>(&property.second);
342 if (address != nullptr)
343 {
344 ipv6_address.address = *address;
345 }
346 }
347 else if (property.first == "Origin")
348 {
349 const std::string *origin =
350 std::get_if<std::string>(&property.second);
351 if (origin != nullptr)
352 {
353 ipv6_address.origin =
354 translateAddressOriginDbusToRedfish(*origin,
355 false);
356 }
357 }
358 else if (property.first == "PrefixLength")
359 {
360 const uint8_t *prefix =
361 std::get_if<uint8_t>(&property.second);
362 if (prefix != nullptr)
363 {
364 ipv6_address.prefixLength = *prefix;
365 }
366 }
367 else
368 {
369 BMCWEB_LOG_ERROR
370 << "Got extra property: " << property.first
371 << " on the " << objpath.first.str << " object";
372 }
373 }
374 if (ipv6_address.origin == "Static")
375 {
376 std::pair<boost::container::flat_set<
377 IPv6AddressData>::iterator,
378 bool>
379 iter = ipv6_static_config.insert(
380 {objpath.first.str.substr(
381 ipv6PathStart.size())});
382 IPv6AddressData &ipv6_static_address = *iter.first;
383
384 ipv6_static_address.address = ipv6_address.address;
385 ipv6_static_address.prefixLength =
386 ipv6_address.prefixLength;
387 }
388 }
389 }
390 }
391 }
392}
393
Ed Tanous4a0cb852018-10-15 07:55:04 -0700394// Helper function that extracts data for single ethernet ipv4 address
395inline void
396 extractIPData(const std::string &ethiface_id,
397 const GetManagedObjects &dbus_data,
398 boost::container::flat_set<IPv4AddressData> &ipv4_config)
399{
400 const std::string ipv4PathStart =
401 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
402
403 // Since there might be several IPv4 configurations aligned with
404 // single ethernet interface, loop over all of them
405 for (const auto &objpath : dbus_data)
406 {
407 // Check if proper pattern for object path appears
408 if (boost::starts_with(objpath.first.str, ipv4PathStart))
409 {
410 for (auto &interface : objpath.second)
411 {
412 if (interface.first == "xyz.openbmc_project.Network.IP")
413 {
414 // Instance IPv4AddressData structure, and set as
415 // appropriate
416 std::pair<
417 boost::container::flat_set<IPv4AddressData>::iterator,
418 bool>
419 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000420 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700421 IPv4AddressData &ipv4_address = *it.first;
422 for (auto &property : interface.second)
423 {
424 if (property.first == "Address")
425 {
426 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800427 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700428 if (address != nullptr)
429 {
430 ipv4_address.address = *address;
431 }
432 }
433 else if (property.first == "Gateway")
434 {
435 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800436 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700437 if (gateway != nullptr)
438 {
439 ipv4_address.gateway = *gateway;
440 }
441 }
442 else if (property.first == "Origin")
443 {
444 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800445 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700446 if (origin != nullptr)
447 {
448 ipv4_address.origin =
449 translateAddressOriginDbusToRedfish(*origin,
450 true);
451 }
452 }
453 else if (property.first == "PrefixLength")
454 {
455 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800456 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700457 if (mask != nullptr)
458 {
459 // convert it to the string
460 ipv4_address.netmask = getNetmask(*mask);
461 }
462 }
463 else
464 {
465 BMCWEB_LOG_ERROR
466 << "Got extra property: " << property.first
467 << " on the " << objpath.first.str << " object";
468 }
469 }
470 // Check if given address is local, or global
471 ipv4_address.linktype =
472 boost::starts_with(ipv4_address.address, "169.254.")
473 ? LinkType::Global
474 : LinkType::Local;
475 }
476 }
477 }
478 }
479}
480
481/**
482 * @brief Sets given Id on the given VLAN interface through D-Bus
483 *
484 * @param[in] ifaceId Id of VLAN interface that should be modified
485 * @param[in] inputVlanId New ID of the VLAN
486 * @param[in] callback Function that will be called after the operation
487 *
488 * @return None.
489 */
490template <typename CallbackFunc>
491void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
492 CallbackFunc &&callback)
493{
494 crow::connections::systemBus->async_method_call(
495 callback, "xyz.openbmc_project.Network",
496 std::string("/xyz/openbmc_project/network/") + ifaceId,
497 "org.freedesktop.DBus.Properties", "Set",
498 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800499 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700500}
501
502/**
503 * @brief Helper function that verifies IP address to check if it is in
504 * proper format. If bits pointer is provided, also calculates active
505 * bit count for Subnet Mask.
506 *
507 * @param[in] ip IP that will be verified
508 * @param[out] bits Calculated mask in bits notation
509 *
510 * @return true in case of success, false otherwise
511 */
512inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
513 uint8_t *bits = nullptr)
514{
515 std::vector<std::string> bytesInMask;
516
517 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518
519 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700520 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700522 return false;
523 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524
Ed Tanous4a0cb852018-10-15 07:55:04 -0700525 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700527 *bits = 0;
528 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529
Ed Tanous4a0cb852018-10-15 07:55:04 -0700530 char *endPtr;
531 long previousValue = 255;
532 bool firstZeroInByteHit;
533 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700535 if (byte.empty())
536 {
537 return false;
538 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539
Ed Tanous4a0cb852018-10-15 07:55:04 -0700540 // Use strtol instead of stroi to avoid exceptions
541 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542
Ed Tanous4a0cb852018-10-15 07:55:04 -0700543 // endPtr should point to the end of the string, otherwise given string
544 // is not 100% number
545 if (*endPtr != '\0')
546 {
547 return false;
548 }
549
550 // Value should be contained in byte
551 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 {
553 return false;
554 }
555
556 if (bits != nullptr)
557 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700558 // Mask has to be continuous between bytes
559 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 {
561 return false;
562 }
563
Ed Tanous4a0cb852018-10-15 07:55:04 -0700564 // Mask has to be continuous inside bytes
565 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566
Ed Tanous4a0cb852018-10-15 07:55:04 -0700567 // Count bits
568 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700570 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700572 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700574 // Continuity not preserved
575 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 }
577 else
578 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700579 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 }
581 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 else
583 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700584 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700586 }
587 }
588
589 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 }
591
Ed Tanous4a0cb852018-10-15 07:55:04 -0700592 return true;
593}
594
595/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000596 * @brief Changes IPv4 address type property (Address, Gateway)
597 *
598 * @param[in] ifaceId Id of interface whose IP should be modified
599 * @param[in] ipIdx Index of IP in input array that should be modified
600 * @param[in] ipHash DBus Hash id of modified IP
601 * @param[in] name Name of field in JSON representation
602 * @param[in] newValue New value that should be written
603 * @param[io] asyncResp Response object that will be returned to client
604 *
605 * @return true if give IP is valid and has been sent do D-Bus, false
606 * otherwise
607 */
608inline void changeIPv4AddressProperty(
609 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
610 const std::string &name, const std::string &newValue,
611 const std::shared_ptr<AsyncResp> asyncResp)
612{
613 auto callback = [asyncResp, ipIdx, name{std::string(name)},
614 newValue{std::move(newValue)}](
615 const boost::system::error_code ec) {
616 if (ec)
617 {
618 messages::internalError(asyncResp->res);
619 }
620 else
621 {
622 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
623 }
624 };
625
626 crow::connections::systemBus->async_method_call(
627 std::move(callback), "xyz.openbmc_project.Network",
628 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
629 "org.freedesktop.DBus.Properties", "Set",
630 "xyz.openbmc_project.Network.IP", name,
631 std::variant<std::string>(newValue));
632}
633
634/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700635 * @brief Changes IPv4 address origin property
636 *
637 * @param[in] ifaceId Id of interface whose IP should be modified
638 * @param[in] ipIdx Index of IP in input array that should be
639 * modified
640 * @param[in] ipHash DBus Hash id of modified IP
641 * @param[in] newValue New value in Redfish format
642 * @param[in] newValueDbus New value in D-Bus format
643 * @param[io] asyncResp Response object that will be returned to client
644 *
645 * @return true if give IP is valid and has been sent do D-Bus, false
646 * otherwise
647 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000648inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700649 const std::string &ipHash,
650 const std::string &newValue,
651 const std::string &newValueDbus,
652 const std::shared_ptr<AsyncResp> asyncResp)
653{
654 auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
655 const boost::system::error_code ec) {
656 if (ec)
657 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800658 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700659 }
660 else
661 {
662 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
663 newValue;
664 }
665 };
666
667 crow::connections::systemBus->async_method_call(
668 std::move(callback), "xyz.openbmc_project.Network",
669 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
670 "org.freedesktop.DBus.Properties", "Set",
671 "xyz.openbmc_project.Network.IP", "Origin",
Ed Tanousabf2add2019-01-22 16:40:12 -0800672 std::variant<std::string>(newValueDbus));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700673}
674
675/**
676 * @brief Modifies SubnetMask for given IP
677 *
678 * @param[in] ifaceId Id of interface whose IP should be modified
679 * @param[in] ipIdx Index of IP in input array that should be
680 * modified
681 * @param[in] ipHash DBus Hash id of modified IP
682 * @param[in] newValueStr Mask in dot notation as string
683 * @param[in] newValue Mask as PrefixLength in bitcount
684 * @param[io] asyncResp Response object that will be returned to client
685 *
686 * @return None
687 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000688inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700689 const std::string &ipHash,
690 const std::string &newValueStr,
691 uint8_t &newValue,
692 std::shared_ptr<AsyncResp> asyncResp)
693{
694 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
695 const boost::system::error_code ec) {
696 if (ec)
697 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800698 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700699 }
700 else
701 {
702 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
703 newValueStr;
704 }
705 };
706
707 crow::connections::systemBus->async_method_call(
708 std::move(callback), "xyz.openbmc_project.Network",
709 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
710 "org.freedesktop.DBus.Properties", "Set",
711 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800712 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700713}
714
715/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700716 * @brief Deletes given IPv4
717 *
718 * @param[in] ifaceId Id of interface whose IP should be deleted
719 * @param[in] ipIdx Index of IP in input array that should be deleted
720 * @param[in] ipHash DBus Hash id of IP that should be deleted
721 * @param[io] asyncResp Response object that will be returned to client
722 *
723 * @return None
724 */
725inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
726 unsigned int ipIdx,
727 const std::shared_ptr<AsyncResp> asyncResp)
728{
729 crow::connections::systemBus->async_method_call(
730 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 if (ec)
732 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800733 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100734 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700735 else
736 {
737 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
738 }
739 },
740 "xyz.openbmc_project.Network",
741 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
742 "xyz.openbmc_project.Object.Delete", "Delete");
743}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744
Ed Tanous4a0cb852018-10-15 07:55:04 -0700745/**
746 * @brief Creates IPv4 with given data
747 *
748 * @param[in] ifaceId Id of interface whose IP should be deleted
749 * @param[in] ipIdx Index of IP in input array that should be deleted
750 * @param[in] ipHash DBus Hash id of IP that should be deleted
751 * @param[io] asyncResp Response object that will be returned to client
752 *
753 * @return None
754 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000755inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
756 uint8_t subnetMask, const std::string &gateway,
757 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700758 std::shared_ptr<AsyncResp> asyncResp)
759{
Ed Tanous43b761d2019-02-13 20:10:56 -0800760 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700761 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800763 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 };
766
Ed Tanous4a0cb852018-10-15 07:55:04 -0700767 crow::connections::systemBus->async_method_call(
768 std::move(createIpHandler), "xyz.openbmc_project.Network",
769 "/xyz/openbmc_project/network/" + ifaceId,
770 "xyz.openbmc_project.Network.IP.Create", "IP",
771 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
772 gateway);
773}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500774
775/**
776 * @brief Deletes given IPv6
777 *
778 * @param[in] ifaceId Id of interface whose IP should be deleted
779 * @param[in] ipHash DBus Hash id of IP that should be deleted
780 * @param[in] ipIdx Index of IP in input array that should be deleted
781 * @param[io] asyncResp Response object that will be returned to client
782 *
783 * @return None
784 */
785inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
786 unsigned int ipIdx,
787 const std::shared_ptr<AsyncResp> asyncResp)
788{
789 crow::connections::systemBus->async_method_call(
790 [ipIdx, asyncResp](const boost::system::error_code ec) {
791 if (ec)
792 {
793 messages::internalError(asyncResp->res);
794 }
795 else
796 {
797 asyncResp->res.jsonValue["IPv6StaticAddresses"][ipIdx] =
798 nullptr;
799 }
800 },
801 "xyz.openbmc_project.Network",
802 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
803 "xyz.openbmc_project.Object.Delete", "Delete");
804}
805
806/**
807 * @brief Creates IPv6 with given data
808 *
809 * @param[in] ifaceId Id of interface whose IP should be added
810 * @param[in] ipIdx Index of IP in input array that should be added
811 * @param[in] prefixLength Prefix length that needs to be added
812 * @param[in] address IP address that needs to be added
813 * @param[io] asyncResp Response object that will be returned to client
814 *
815 * @return None
816 */
817inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
818 uint8_t prefixLength, const std::string &address,
819 std::shared_ptr<AsyncResp> asyncResp)
820{
821 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
822 if (ec)
823 {
824 messages::internalError(asyncResp->res);
825 }
826 };
827 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
828 // does not have assosiated gateway property
829 crow::connections::systemBus->async_method_call(
830 std::move(createIpHandler), "xyz.openbmc_project.Network",
831 "/xyz/openbmc_project/network/" + ifaceId,
832 "xyz.openbmc_project.Network.IP.Create", "IP",
833 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
834 "");
835}
836
manojkiraneda2a133282019-02-19 13:09:43 +0530837using GetAllPropertiesType =
838 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
839
840inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
841{
842 auto getConfig = [asyncResp](const boost::system::error_code error_code,
843 const GetAllPropertiesType &dbus_data) {
844 if (error_code)
845 {
846 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
847 messages::internalError(asyncResp->res);
848 return;
849 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500850 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530851 for (const auto &property : dbus_data)
852 {
853 auto value =
854 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
855
856 if (value == nullptr)
857 {
858 continue;
859 }
860 if (property.first == "DNSEnabled")
861 {
862 DHCPConfigTypeJson["UseDNSServers"] = *value;
863 }
864 else if (property.first == "HostNameEnabled")
865 {
866 DHCPConfigTypeJson["UseDomainName"] = *value;
867 }
868 else if (property.first == "NTPEnabled")
869 {
870 DHCPConfigTypeJson["UseNTPServers"] = *value;
871 }
872 }
873 };
874 crow::connections::systemBus->async_method_call(
875 std::move(getConfig), "xyz.openbmc_project.Network",
876 "/xyz/openbmc_project/network/config/dhcp",
877 "org.freedesktop.DBus.Properties", "GetAll",
878 "xyz.openbmc_project.Network.DHCPConfiguration");
879}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880
Ed Tanous4a0cb852018-10-15 07:55:04 -0700881/**
882 * Function that retrieves all properties for given Ethernet Interface
883 * Object
884 * from EntityManager Network Manager
885 * @param ethiface_id a eth interface id to query on DBus
886 * @param callback a function that shall be called to convert Dbus output
887 * into JSON
888 */
889template <typename CallbackFunc>
890void getEthernetIfaceData(const std::string &ethiface_id,
891 CallbackFunc &&callback)
892{
893 crow::connections::systemBus->async_method_call(
894 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
895 const boost::system::error_code error_code,
896 const GetManagedObjects &resp) {
897 EthernetInterfaceData ethData{};
898 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500899 boost::container::flat_set<IPv6AddressData> ipv6Data;
900 boost::container::flat_set<IPv6AddressData> ipv6StaticData;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700901
902 if (error_code)
903 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500904 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700905 return;
906 }
907
Ed Tanous4c9afe42019-05-03 16:59:57 -0700908 bool found =
909 extractEthernetInterfaceData(ethiface_id, resp, ethData);
910 if (!found)
911 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500912 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700913 return;
914 }
915
Ed Tanous4a0cb852018-10-15 07:55:04 -0700916 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700917 // Fix global GW
918 for (IPv4AddressData &ipv4 : ipv4Data)
919 {
920 if ((ipv4.linktype == LinkType::Global) &&
921 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700923 ipv4.gateway = ethData.default_gateway;
924 }
925 }
926
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500927 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700928 // Finally make a callback with usefull data
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500929 callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700930 },
931 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
932 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
933};
934
935/**
936 * Function that retrieves all Ethernet Interfaces available through Network
937 * Manager
938 * @param callback a function that shall be called to convert Dbus output
939 * into JSON.
940 */
941template <typename CallbackFunc>
942void getEthernetIfaceList(CallbackFunc &&callback)
943{
944 crow::connections::systemBus->async_method_call(
945 [callback{std::move(callback)}](
946 const boost::system::error_code error_code,
947 GetManagedObjects &resp) {
948 // Callback requires vector<string> to retrieve all available
949 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700950 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700951 iface_list.reserve(resp.size());
952 if (error_code)
953 {
954 callback(false, iface_list);
955 return;
956 }
957
958 // Iterate over all retrieved ObjectPaths.
959 for (const auto &objpath : resp)
960 {
961 // And all interfaces available for certain ObjectPath.
962 for (const auto &interface : objpath.second)
963 {
964 // If interface is
965 // xyz.openbmc_project.Network.EthernetInterface, this is
966 // what we're looking for.
967 if (interface.first ==
968 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700970 // Cut out everyting until last "/", ...
971 const std::string &iface_id = objpath.first.str;
972 std::size_t last_pos = iface_id.rfind("/");
973 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700974 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700975 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700976 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977 }
978 }
979 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700980 }
981 // Finally make a callback with useful data
982 callback(true, iface_list);
983 },
984 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
985 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100986};
987
988/**
989 * EthernetCollection derived class for delivering Ethernet Collection Schema
990 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700991class EthernetCollection : public Node
992{
993 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700994 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700996 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700998 entityPrivileges = {
999 {boost::beast::http::verb::get, {{"Login"}}},
1000 {boost::beast::http::verb::head, {{"Login"}}},
1001 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1002 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1003 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1004 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1005 }
1006
1007 private:
1008 /**
1009 * Functions triggers appropriate requests on DBus
1010 */
1011 void doGet(crow::Response &res, const crow::Request &req,
1012 const std::vector<std::string> &params) override
1013 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001014 res.jsonValue["@odata.type"] =
1015 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
1016 res.jsonValue["@odata.context"] =
1017 "/redfish/v1/"
1018 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
1019 res.jsonValue["@odata.id"] =
1020 "/redfish/v1/Managers/bmc/EthernetInterfaces";
1021 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
1022 res.jsonValue["Description"] =
1023 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -07001024 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001025 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001026 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001027 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -07001028 [asyncResp](
1029 const bool &success,
1030 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001031 if (!success)
1032 {
Ed Tanous4c9afe42019-05-03 16:59:57 -07001033 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -07001034 return;
1035 }
1036
Ed Tanous4c9afe42019-05-03 16:59:57 -07001037 nlohmann::json &iface_array =
1038 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -07001039 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001040 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -07001041 for (const std::string &iface_item : iface_list)
1042 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001043 std::size_t found = iface_item.find(tag);
1044 if (found == std::string::npos)
1045 {
1046 iface_array.push_back(
1047 {{"@odata.id",
1048 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1049 iface_item}});
1050 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001051 }
1052
Ed Tanous4c9afe42019-05-03 16:59:57 -07001053 asyncResp->res.jsonValue["Members@odata.count"] =
1054 iface_array.size();
1055 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -07001056 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -07001057 });
Ed Tanous4a0cb852018-10-15 07:55:04 -07001058 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001059};
1060
1061/**
1062 * EthernetInterface derived class for delivering Ethernet Schema
1063 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001064class EthernetInterface : public Node
1065{
1066 public:
1067 /*
1068 * Default Constructor
1069 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001070 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001071 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001072 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001073 std::string())
1074 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001075 entityPrivileges = {
1076 {boost::beast::http::verb::get, {{"Login"}}},
1077 {boost::beast::http::verb::head, {{"Login"}}},
1078 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1079 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1080 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1081 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001082 }
1083
Ed Tanous1abe55e2018-09-05 08:30:59 -07001084 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001085 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001086 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001087 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001088 asyncResp->res.jsonValue["HostName"] = hostname;
1089 crow::connections::systemBus->async_method_call(
1090 [asyncResp](const boost::system::error_code ec) {
1091 if (ec)
1092 {
1093 messages::internalError(asyncResp->res);
1094 }
1095 },
1096 "xyz.openbmc_project.Network",
1097 "/xyz/openbmc_project/network/config",
1098 "org.freedesktop.DBus.Properties", "Set",
1099 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001100 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001101 }
1102
Ratan Guptad5776652019-03-03 08:47:22 +05301103 void handleMACAddressPatch(const std::string &ifaceId,
1104 const std::string &macAddress,
1105 const std::shared_ptr<AsyncResp> &asyncResp)
1106 {
1107 crow::connections::systemBus->async_method_call(
1108 [asyncResp, macAddress](const boost::system::error_code ec) {
1109 if (ec)
1110 {
1111 messages::internalError(asyncResp->res);
1112 return;
1113 }
1114 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
1115 },
1116 "xyz.openbmc_project.Network",
1117 "/xyz/openbmc_project/network/" + ifaceId,
1118 "org.freedesktop.DBus.Properties", "Set",
1119 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1120 std::variant<std::string>(macAddress));
1121 }
Jennifer Leeda131a92019-04-24 15:13:55 -07001122 void setDHCPEnabled(const std::string &ifaceId,
1123 const std::string &propertyName, const bool &value,
1124 const std::shared_ptr<AsyncResp> asyncResp)
1125 {
1126 crow::connections::systemBus->async_method_call(
1127 [asyncResp](const boost::system::error_code ec) {
1128 if (ec)
1129 {
1130 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1131 messages::internalError(asyncResp->res);
1132 return;
1133 }
1134 },
1135 "xyz.openbmc_project.Network",
1136 "/xyz/openbmc_project/network/" + ifaceId,
1137 "org.freedesktop.DBus.Properties", "Set",
1138 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1139 std::variant<bool>{value});
1140 }
1141 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1142 const std::shared_ptr<AsyncResp> asyncResp)
1143 {
1144 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1145 crow::connections::systemBus->async_method_call(
1146 [asyncResp](const boost::system::error_code ec) {
1147 if (ec)
1148 {
1149 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1150 messages::internalError(asyncResp->res);
1151 return;
1152 }
1153 },
1154 "xyz.openbmc_project.Network",
1155 "/xyz/openbmc_project/network/config/dhcp",
1156 "org.freedesktop.DBus.Properties", "Set",
1157 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1158 std::variant<bool>{value});
1159 }
Ratan Guptad5776652019-03-03 08:47:22 +05301160
Jennifer Leeda131a92019-04-24 15:13:55 -07001161 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1162 const std::shared_ptr<AsyncResp> asyncResp)
1163 {
1164 std::optional<bool> dhcpEnabled;
1165 std::optional<bool> useDNSServers;
1166 std::optional<bool> useDomainName;
1167 std::optional<bool> useNTPServers;
1168
1169 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1170 dhcpEnabled, "UseDNSServers", useDNSServers,
1171 "UseDomainName", useDomainName,
1172 "UseNTPServers", useNTPServers))
1173 {
1174 return;
1175 }
1176
1177 if (dhcpEnabled)
1178 {
1179 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1180 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1181 }
1182
1183 if (useDNSServers)
1184 {
1185 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1186 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1187 }
1188
1189 if (useDomainName)
1190 {
1191 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1192 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1193 }
1194
1195 if (useNTPServers)
1196 {
1197 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1198 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1199 }
1200 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001201 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301202 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001203 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1204 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001205 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301206 if (!input.is_array())
1207 {
1208 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1209 "IPv4Addresses");
1210 return;
1211 }
1212
Ed Tanous4a0cb852018-10-15 07:55:04 -07001213 int entryIdx = 0;
1214 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1215 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001216 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001217 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001218 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001219 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220
Ratan Guptaf476acb2019-03-02 16:46:57 +05301221 if (thisJson.is_null())
1222 {
1223 if (thisData != ipv4Data.end())
1224 {
1225 deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
1226 thisData++;
1227 }
1228 else
1229 {
1230 messages::propertyValueFormatError(
1231 asyncResp->res, input.dump(), pathString);
1232 return;
1233 // TODO(ratagupt) Not sure about the property where value is
1234 // list and if unable to update one of the
1235 // list value then should we proceed further or
1236 // break there, would ask in the redfish forum
1237 // till then we stop processing the next list item.
1238 }
1239 entryIdx++;
1240 continue; // not an error as per the redfish spec.
1241 }
1242
Ratan Gupta9474b372019-03-01 15:13:37 +05301243 if (thisJson.empty())
1244 {
1245 if (thisData != ipv4Data.end())
1246 {
1247 thisData++;
1248 }
1249 else
1250 {
1251 messages::propertyMissing(asyncResp->res,
1252 pathString + "/Address");
1253 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301254 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301255 // list and if unable to update one of the
1256 // list value then should we proceed further or
1257 // break there, would ask in the redfish forum
1258 // till then we stop processing the next list item.
1259 }
1260 entryIdx++;
1261 continue; // not an error as per the redfish spec.
1262 }
1263
Ed Tanous537174c2018-12-10 15:09:31 -08001264 std::optional<std::string> address;
1265 std::optional<std::string> addressOrigin;
1266 std::optional<std::string> subnetMask;
1267 std::optional<std::string> gateway;
1268
1269 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1270 address, "AddressOrigin", addressOrigin,
1271 "SubnetMask", subnetMask, "Gateway",
1272 gateway))
1273 {
1274 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001275 }
1276
Ed Tanous537174c2018-12-10 15:09:31 -08001277 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001278 {
Ed Tanous537174c2018-12-10 15:09:31 -08001279 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001280 {
Ed Tanous537174c2018-12-10 15:09:31 -08001281 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001282 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001283 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001284 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001285 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001286
Ed Tanous537174c2018-12-10 15:09:31 -08001287 uint8_t prefixLength = 0;
1288 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001289 {
Ed Tanous537174c2018-12-10 15:09:31 -08001290 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001291 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001292 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001293 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001294 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001295 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001296 }
1297 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001298 std::string addressOriginInDBusFormat;
Ed Tanous537174c2018-12-10 15:09:31 -08001299 if (addressOrigin)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001300 {
Ed Tanous537174c2018-12-10 15:09:31 -08001301 // Get Address origin in proper format
1302 addressOriginInDBusFormat =
1303 translateAddressOriginRedfishToDbus(*addressOrigin);
1304 if (addressOriginInDBusFormat.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001305 {
Ed Tanous537174c2018-12-10 15:09:31 -08001306 messages::propertyValueNotInList(
1307 asyncResp->res, *addressOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001308 pathString + "/AddressOrigin");
Ed Tanous537174c2018-12-10 15:09:31 -08001309 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001310 }
1311 }
1312
Ed Tanous537174c2018-12-10 15:09:31 -08001313 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001314 {
Ed Tanous537174c2018-12-10 15:09:31 -08001315 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001316 {
Ed Tanous537174c2018-12-10 15:09:31 -08001317 messages::propertyValueFormatError(asyncResp->res, *gateway,
1318 pathString + "/Gateway");
1319 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001320 }
1321 }
1322
Ratan Guptaf476acb2019-03-02 16:46:57 +05301323 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001324 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001325 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301326 // Apply changes
1327 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001328 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301329 auto callback = [asyncResp, entryIdx,
1330 address{std::string(*address)}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001331 const boost::system::error_code ec) {
1332 if (ec)
1333 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001334 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001335 return;
1336 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301337 asyncResp->res
1338 .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1339 std::move(address);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001340 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301341
Ed Tanous4a0cb852018-10-15 07:55:04 -07001342 crow::connections::systemBus->async_method_call(
1343 std::move(callback), "xyz.openbmc_project.Network",
1344 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1345 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301346 "org.freedesktop.DBus.Properties", "Set",
1347 "xyz.openbmc_project.Network.IP", "Address",
1348 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001349 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301350
1351 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001352 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301353 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1354 thisData->id, *subnetMask,
1355 prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001356 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301357
1358 if (addressOrigin)
1359 {
1360 changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1361 *addressOrigin, addressOriginInDBusFormat,
1362 asyncResp);
1363 }
1364
1365 if (gateway)
1366 {
1367 auto callback = [asyncResp, entryIdx,
1368 gateway{std::string(*gateway)}](
1369 const boost::system::error_code ec) {
1370 if (ec)
1371 {
1372 messages::internalError(asyncResp->res);
1373 return;
1374 }
1375 asyncResp->res
1376 .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1377 std::move(gateway);
1378 };
1379
1380 crow::connections::systemBus->async_method_call(
1381 std::move(callback), "xyz.openbmc_project.Network",
1382 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1383 thisData->id,
1384 "org.freedesktop.DBus.Properties", "Set",
1385 "xyz.openbmc_project.Network.IP", "Gateway",
1386 std::variant<std::string>(*gateway));
1387 }
1388
Ed Tanous4a0cb852018-10-15 07:55:04 -07001389 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001390 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001391 else
1392 {
1393 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001394 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001395 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001396 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001397 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001398 continue;
1399 }
1400
Ed Tanous537174c2018-12-10 15:09:31 -08001401 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001402 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001403 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001404 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001405 continue;
1406 }
1407
Ed Tanous537174c2018-12-10 15:09:31 -08001408 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001409 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001410 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001411 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001412 continue;
1413 }
1414
Ed Tanousb01bf292019-03-25 19:25:26 +00001415 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1416 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301417
1418 nlohmann::json &ipv4AddressJson =
1419 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1420 ipv4AddressJson["Address"] = *address;
1421 ipv4AddressJson["SubnetMask"] = *subnetMask;
1422 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001423 }
1424 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001425 }
1426 }
1427
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001428 void handleStaticNameServersPatch(
1429 const std::string &ifaceId,
1430 const std::vector<std::string> &updatedStaticNameServers,
1431 const std::shared_ptr<AsyncResp> &asyncResp)
1432 {
1433 crow::connections::systemBus->async_method_call(
1434 [asyncResp,
1435 updatedStaticNameServers](const boost::system::error_code ec) {
1436 if (ec)
1437 {
1438 messages::internalError(asyncResp->res);
1439 return;
1440 }
1441 asyncResp->res.jsonValue["NameServers"] =
1442 updatedStaticNameServers;
1443 asyncResp->res.jsonValue["StaticNameServers"] =
1444 updatedStaticNameServers;
1445 },
1446 "xyz.openbmc_project.Network",
1447 "/xyz/openbmc_project/network/" + ifaceId,
1448 "org.freedesktop.DBus.Properties", "Set",
1449 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1450 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1451 }
1452
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001453 void handleIPv6StaticAddressesPatch(
1454 const std::string &ifaceId, nlohmann::json &input,
1455 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1456 const std::shared_ptr<AsyncResp> asyncResp)
1457 {
1458 if (!input.is_array())
1459 {
1460 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1461 "IPv6StaticAddresses");
1462 return;
1463 }
1464
1465 int entryIdx = 0;
1466 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1467 ipv6StaticData.begin();
1468 for (nlohmann::json &thisJson : input)
1469 {
1470 std::string pathString =
1471 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1472
1473 if (thisJson.is_null())
1474 {
1475 if (thisData != ipv6StaticData.end())
1476 {
1477 deleteIPv6(ifaceId, thisData->id, entryIdx, asyncResp);
1478 thisData++;
1479 }
1480 else
1481 {
1482 messages::propertyValueFormatError(
1483 asyncResp->res, input.dump(), pathString);
1484 return;
1485 }
1486 entryIdx++;
1487 continue;
1488 }
1489
1490 if (thisJson.empty())
1491 {
1492 if (thisData != ipv6StaticData.end())
1493 {
1494 thisData++;
1495 }
1496 else
1497 {
1498 messages::propertyMissing(asyncResp->res,
1499 pathString + "/Address");
1500 return;
1501 }
1502 entryIdx++;
1503 continue;
1504 }
1505
1506 std::optional<std::string> address;
1507 std::optional<uint8_t> prefixLength;
1508
1509 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1510 address, "PrefixLength", prefixLength))
1511 {
1512 return;
1513 }
1514
1515 // if IP address exist then modify it.
1516 if (thisData != ipv6StaticData.end())
1517 {
1518 // Apply changes
1519 if (address)
1520 {
1521 auto callback = [asyncResp, entryIdx,
1522 address{std::string(*address)}](
1523 const boost::system::error_code ec) {
1524 if (ec)
1525 {
1526 messages::internalError(asyncResp->res);
1527 return;
1528 }
1529 asyncResp->res.jsonValue["IPv6StaticAddresses"]
1530 [entryIdx]["Address"] =
1531 std::move(address);
1532 };
1533
1534 crow::connections::systemBus->async_method_call(
1535 std::move(callback), "xyz.openbmc_project.Network",
1536 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1537 thisData->id,
1538 "org.freedesktop.DBus.Properties", "Set",
1539 "xyz.openbmc_project.Network.IP", "Address",
1540 std::variant<std::string>(*address));
1541 }
1542
1543 if (prefixLength)
1544 {
1545 auto callback = [asyncResp, entryIdx,
1546 prefixLength{uint8_t(*prefixLength)}](
1547 const boost::system::error_code ec) {
1548 if (ec)
1549 {
1550 messages::internalError(asyncResp->res);
1551 return;
1552 }
1553 asyncResp->res.jsonValue["IPv6StaticAddresses"]
1554 [entryIdx]["PrefixLength"] =
1555 std::move(prefixLength);
1556 };
1557
1558 crow::connections::systemBus->async_method_call(
1559 std::move(callback), "xyz.openbmc_project.Network",
1560 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1561 thisData->id,
1562 "org.freedesktop.DBus.Properties", "Set",
1563 "xyz.openbmc_project.Network.IP", "PrefixLength",
1564 std::variant<uint8_t>(*prefixLength));
1565 }
1566
1567 thisData++;
1568 }
1569 else
1570 {
1571 // Create IPv6 with provided data
1572
1573 if (!prefixLength)
1574 {
1575 messages::propertyMissing(asyncResp->res,
1576 pathString + "/PrefixLength");
1577 continue;
1578 }
1579
1580 if (!address)
1581 {
1582 messages::propertyMissing(asyncResp->res,
1583 pathString + "/Address");
1584 continue;
1585 }
1586
1587 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1588 asyncResp);
1589
1590 nlohmann::json &ipv6StaticAddressJson =
1591 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1592 ipv6StaticAddressJson["Address"] = *address;
1593 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1594 }
1595 entryIdx++;
1596 }
1597 }
1598
Ed Tanous0f74e642018-11-12 15:17:05 -08001599 void parseInterfaceData(
1600 nlohmann::json &json_response, const std::string &iface_id,
1601 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001602 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1603 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1604 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001605 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001606 json_response["Id"] = iface_id;
1607 json_response["@odata.id"] =
1608 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001609 json_response["InterfaceEnabled"] = true;
1610 if (ethData.speed == 0)
1611 {
1612 json_response["LinkStatus"] = "NoLink";
1613 json_response["Status"] = {
1614 {"Health", "OK"},
1615 {"State", "Disabled"},
1616 };
1617 }
1618 else
1619 {
1620 json_response["LinkStatus"] = "LinkUp";
1621 json_response["Status"] = {
1622 {"Health", "OK"},
1623 {"State", "Enabled"},
1624 };
1625 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001626 json_response["SpeedMbps"] = ethData.speed;
1627 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001628 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301629
Ed Tanous4a0cb852018-10-15 07:55:04 -07001630 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001631 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001632 json_response["HostName"] = ethData.hostname;
1633 }
1634
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001635 json_response["VLANs"] = {
1636 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1637 iface_id + "/VLANs"}};
1638
Ed Tanous029573d2019-02-01 10:57:49 -08001639 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001640 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001641
Ed Tanous4a0cb852018-10-15 07:55:04 -07001642 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001644 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1645 ipv4_array = nlohmann::json::array();
1646 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001647 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001648
1649 std::string gatewayStr = ipv4_config.gateway;
1650 if (gatewayStr.empty())
1651 {
1652 gatewayStr = "0.0.0.0";
1653 }
1654
Ed Tanous029573d2019-02-01 10:57:49 -08001655 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1656 {"SubnetMask", ipv4_config.netmask},
1657 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001658 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001661 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001662
1663 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1664 ipv6_array = nlohmann::json::array();
1665 for (auto &ipv6_config : ipv6Data)
1666 {
1667 ipv6_array.push_back({{"Address", ipv6_config.address},
1668 {"PrefixLength", ipv6_config.prefixLength},
1669 {"AddressOrigin", ipv6_config.origin}});
1670 }
1671
1672 nlohmann::json &ipv6_static_array =
1673 json_response["IPv6StaticAddresses"];
1674 ipv6_static_array = nlohmann::json::array();
1675 for (auto &ipv6_static_config : ipv6StaticData)
1676 {
1677 ipv6_static_array.push_back(
1678 {{"Address", ipv6_static_config.address},
1679 {"PrefixLength", ipv6_static_config.prefixLength}});
1680 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001681 }
1682
1683 /**
1684 * Functions triggers appropriate requests on DBus
1685 */
1686 void doGet(crow::Response &res, const crow::Request &req,
1687 const std::vector<std::string> &params) override
1688 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001689 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001690 if (params.size() != 1)
1691 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001692 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001693 return;
1694 }
1695
Ed Tanous4a0cb852018-10-15 07:55:04 -07001696 getEthernetIfaceData(
1697 params[0],
1698 [this, asyncResp, iface_id{std::string(params[0])}](
1699 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001700 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1701 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1702 const boost::container::flat_set<IPv6AddressData>
1703 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001704 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001705 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 // TODO(Pawel)consider distinguish between non existing
1707 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001708 messages::resourceNotFound(asyncResp->res,
1709 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001710 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001712
1713 // because this has no dependence on the interface at this
1714 // point, it needs to be done after we know the interface
1715 // exists, not before.
1716 getDHCPConfigData(asyncResp);
1717
Ed Tanous0f74e642018-11-12 15:17:05 -08001718 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001719 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001720 asyncResp->res.jsonValue["@odata.context"] =
1721 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1722 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1723 asyncResp->res.jsonValue["Description"] =
1724 "Management Network Interface";
1725
1726 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001727 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728 });
1729 }
1730
1731 void doPatch(crow::Response &res, const crow::Request &req,
1732 const std::vector<std::string> &params) override
1733 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001734 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 if (params.size() != 1)
1736 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001737 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001738 return;
1739 }
1740
Ed Tanous4a0cb852018-10-15 07:55:04 -07001741 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001743 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301744 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001745 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301746 std::optional<nlohmann::json> ipv4Addresses;
1747 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001748 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001749 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001750 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001751 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001752
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001753 if (!json_util::readJson(
1754 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Johnathan Mantey6ca6ac12019-06-10 12:21:31 -07001755 "MACAddress", macAddress, "StaticNameServers",
1756 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
1757 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
1758 nameServers, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001759 {
1760 return;
1761 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301762
Jennifer Leeda131a92019-04-24 15:13:55 -07001763 if (dhcpv4)
1764 {
1765 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1766 }
1767
Ed Tanous4a0cb852018-10-15 07:55:04 -07001768 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001769 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001770 getEthernetIfaceData(
1771 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001772 [this, asyncResp, iface_id, hostname = std::move(hostname),
1773 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001774 ipv4Addresses = std::move(ipv4Addresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001775 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001776 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001777 staticNameServers = std::move(staticNameServers),
1778 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001779 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001780 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1781 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1782 const boost::container::flat_set<IPv6AddressData>
1783 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 if (!success)
1785 {
1786 // ... otherwise return error
1787 // TODO(Pawel)consider distinguish between non existing
1788 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001789 messages::resourceNotFound(asyncResp->res,
1790 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 return;
1792 }
1793
Ed Tanous0f74e642018-11-12 15:17:05 -08001794 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001795 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001796
Ed Tanous0627a2c2018-11-29 17:09:23 -08001797 if (hostname)
1798 {
1799 handleHostnamePatch(*hostname, asyncResp);
1800 }
1801
Ratan Guptad5776652019-03-03 08:47:22 +05301802 if (macAddress)
1803 {
1804 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1805 }
1806
Ed Tanous0627a2c2018-11-29 17:09:23 -08001807 if (ipv4Addresses)
1808 {
Ed Tanous537174c2018-12-10 15:09:31 -08001809 // TODO(ed) for some reason the capture of ipv4Addresses
1810 // above is returning a const value, not a non-const value.
1811 // This doesn't really work for us, as we need to be able to
1812 // efficiently move out the intermedia nlohmann::json
1813 // objects. This makes a copy of the structure, and operates
1814 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301815 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001816 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001817 }
1818
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001819 if (nameServers)
1820 {
1821 // Data.Permissions is read-only
1822 messages::propertyNotWritable(asyncResp->res,
1823 "NameServers");
1824 }
1825
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001826 if (staticNameServers)
1827 {
1828 handleStaticNameServersPatch(iface_id, *staticNameServers,
1829 asyncResp);
1830 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001831
1832 if (ipv6DefaultGateway)
1833 {
1834 messages::propertyNotWritable(asyncResp->res,
1835 "IPv6DefaultGateway");
1836 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001837
1838 if (ipv6StaticAddresses)
1839 {
1840 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1841 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1842 ipv6StaticData, asyncResp);
1843
1844 // call getEthernetIfaceData to populate updated static
1845 // addresses data to "IPv6Addresses" json collection
1846 getEthernetIfaceData(
1847 iface_id,
1848 [this, asyncResp, iface_id](
1849 const bool &success,
1850 const EthernetInterfaceData &ethData,
1851 const boost::container::flat_set<IPv4AddressData>
1852 &ipv4Data,
1853 const boost::container::flat_set<IPv6AddressData>
1854 &ipv6Data,
1855 const boost::container::flat_set<IPv6AddressData>
1856 &ipv6StaticData) {
1857 if (!success)
1858 {
1859 messages::resourceNotFound(asyncResp->res,
1860 "Ethernet Interface",
1861 iface_id);
1862 return;
1863 }
1864
1865 parseInterfaceData(asyncResp->res.jsonValue,
1866 iface_id, ethData, ipv4Data,
1867 ipv6Data, ipv6StaticData);
1868 });
1869 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 });
1871 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001872};
1873
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001874/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001875 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1876 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001877 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878class VlanNetworkInterface : public Node
1879{
1880 public:
1881 /*
1882 * Default Constructor
1883 */
1884 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001885 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001886 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001887 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001888 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001889 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001890 entityPrivileges = {
1891 {boost::beast::http::verb::get, {{"Login"}}},
1892 {boost::beast::http::verb::head, {{"Login"}}},
1893 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1894 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1895 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1896 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001897 }
1898
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001900 void parseInterfaceData(
1901 nlohmann::json &json_response, const std::string &parent_iface_id,
1902 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001903 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1904 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1905 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001906 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001908 json_response["Id"] = iface_id;
1909 json_response["@odata.id"] =
1910 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1911 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001912
Ed Tanous4a0cb852018-10-15 07:55:04 -07001913 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001914 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001915 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001916 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001917 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001918 }
1919
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001920 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 {
1922 if (!boost::starts_with(iface, parent + "_"))
1923 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001924 return false;
1925 }
1926 else
1927 {
1928 return true;
1929 }
1930 }
1931
1932 /**
1933 * Functions triggers appropriate requests on DBus
1934 */
1935 void doGet(crow::Response &res, const crow::Request &req,
1936 const std::vector<std::string> &params) override
1937 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001938 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1939 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001940 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1941 // Check if there is required param, truly entering this shall be
1942 // impossible.
1943 if (params.size() != 2)
1944 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001945 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001946 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001947 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001948 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001949
Ed Tanous4a0cb852018-10-15 07:55:04 -07001950 const std::string &parent_iface_id = params[0];
1951 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001952 res.jsonValue["@odata.type"] =
1953 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1954 res.jsonValue["@odata.context"] =
1955 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1956 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001957
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001958 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001959 {
1960 return;
1961 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001962
Ed Tanous1abe55e2018-09-05 08:30:59 -07001963 // Get single eth interface data, and call the below callback for JSON
1964 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001965 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001966 params[1],
1967 [this, asyncResp, parent_iface_id{std::string(params[0])},
1968 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001969 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001970 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1971 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1972 const boost::container::flat_set<IPv6AddressData>
1973 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001974 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001975 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001976 parseInterfaceData(asyncResp->res.jsonValue,
1977 parent_iface_id, iface_id, ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001978 ipv4Data, ipv6Data, ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001979 }
1980 else
1981 {
1982 // ... otherwise return error
1983 // TODO(Pawel)consider distinguish between non existing
1984 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001985 messages::resourceNotFound(
1986 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001987 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001988 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001989 }
1990
Ed Tanous1abe55e2018-09-05 08:30:59 -07001991 void doPatch(crow::Response &res, const crow::Request &req,
1992 const std::vector<std::string> &params) override
1993 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001994 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001995 if (params.size() != 2)
1996 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001997 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001998 return;
1999 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002000
Ed Tanous1abe55e2018-09-05 08:30:59 -07002001 const std::string &parentIfaceId = params[0];
2002 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002003
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002004 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002005 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002006 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2007 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002008 return;
2009 }
2010
Ed Tanous0627a2c2018-11-29 17:09:23 -08002011 bool vlanEnable = false;
2012 uint64_t vlanId = 0;
2013
2014 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
2015 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016 {
2017 return;
2018 }
2019
2020 // Get single eth interface data, and call the below callback for JSON
2021 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002022 getEthernetIfaceData(
2023 params[1],
2024 [this, asyncResp, parentIfaceId{std::string(params[0])},
2025 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
2026 const bool &success, const EthernetInterfaceData &ethData,
2027 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2028 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2029 const boost::container::flat_set<IPv6AddressData>
2030 &ipv6StaticData) {
2031 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05002032 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002033 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
2034 ifaceId, ethData, ipv4Data, ipv6Data,
2035 ipv6StaticData);
2036 auto callback =
2037 [asyncResp](const boost::system::error_code ec) {
2038 if (ec)
2039 {
2040 messages::internalError(asyncResp->res);
2041 }
2042 };
2043
2044 if (vlanEnable == true)
2045 {
2046 crow::connections::systemBus->async_method_call(
2047 std::move(callback), "xyz.openbmc_project.Network",
2048 "/xyz/openbmc_project/network/" + ifaceId,
2049 "org.freedesktop.DBus.Properties", "Set",
2050 "xyz.openbmc_project.Network.VLAN", "Id",
2051 std::variant<uint32_t>(vlanId));
2052 }
2053 else
2054 {
2055 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
2056 "vlan interface";
2057 crow::connections::systemBus->async_method_call(
2058 std::move(callback), "xyz.openbmc_project.Network",
2059 std::string("/xyz/openbmc_project/network/") +
2060 ifaceId,
2061 "xyz.openbmc_project.Object.Delete", "Delete");
2062 }
Sunitha Harish08244d02019-04-01 03:57:25 -05002063 }
2064 else
2065 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002066 // TODO(Pawel)consider distinguish between non existing
2067 // object, and other errors
2068 messages::resourceNotFound(
2069 asyncResp->res, "VLAN Network Interface", ifaceId);
2070 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05002071 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002072 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002073 }
2074
2075 void doDelete(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() != 2)
2080 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002081 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002082 return;
2083 }
2084
2085 const std::string &parentIfaceId = params[0];
2086 const std::string &ifaceId = params[1];
2087
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002088 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002089 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002090 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2091 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002092 return;
2093 }
2094
2095 // Get single eth interface data, and call the below callback for JSON
2096 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002097 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002098 params[1],
2099 [this, asyncResp, parentIfaceId{std::string(params[0])},
2100 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002101 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002102 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2103 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2104 const boost::container::flat_set<IPv6AddressData>
2105 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002106 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002107 {
Ed Tanous0f74e642018-11-12 15:17:05 -08002108 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002109 ifaceId, ethData, ipv4Data, ipv6Data,
2110 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002111
Jason M. Billsf12894f2018-10-09 12:45:45 -07002112 auto callback =
2113 [asyncResp](const boost::system::error_code ec) {
2114 if (ec)
2115 {
2116 messages::internalError(asyncResp->res);
2117 }
2118 };
2119 crow::connections::systemBus->async_method_call(
2120 std::move(callback), "xyz.openbmc_project.Network",
2121 std::string("/xyz/openbmc_project/network/") + ifaceId,
2122 "xyz.openbmc_project.Object.Delete", "Delete");
2123 }
2124 else
2125 {
2126 // ... otherwise return error
2127 // TODO(Pawel)consider distinguish between non existing
2128 // object, and other errors
2129 messages::resourceNotFound(
2130 asyncResp->res, "VLAN Network Interface", ifaceId);
2131 }
2132 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002133 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002134};
2135
2136/**
2137 * VlanNetworkInterfaceCollection derived class for delivering
2138 * VLANNetworkInterface Collection Schema
2139 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002140class VlanNetworkInterfaceCollection : public Node
2141{
2142 public:
2143 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002144 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002145 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2146 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002147 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002148 entityPrivileges = {
2149 {boost::beast::http::verb::get, {{"Login"}}},
2150 {boost::beast::http::verb::head, {{"Login"}}},
2151 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2152 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2153 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2154 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002155 }
2156
Ed Tanous1abe55e2018-09-05 08:30:59 -07002157 private:
2158 /**
2159 * Functions triggers appropriate requests on DBus
2160 */
2161 void doGet(crow::Response &res, const crow::Request &req,
2162 const std::vector<std::string> &params) override
2163 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002164 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002165 if (params.size() != 1)
2166 {
2167 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002168 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002169 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002170 }
2171
Ed Tanous4a0cb852018-10-15 07:55:04 -07002172 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002173
Ed Tanous4a0cb852018-10-15 07:55:04 -07002174 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002175 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002176 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002177 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002178 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002179 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002180 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002181 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002182 messages::internalError(asyncResp->res);
2183 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002184 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002185
2186 if (iface_list.find(rootInterfaceName) == iface_list.end())
2187 {
2188 messages::resourceNotFound(asyncResp->res,
2189 "VLanNetworkInterfaceCollection",
2190 rootInterfaceName);
2191 return;
2192 }
2193
Ed Tanous0f74e642018-11-12 15:17:05 -08002194 asyncResp->res.jsonValue["@odata.type"] =
2195 "#VLanNetworkInterfaceCollection."
2196 "VLanNetworkInterfaceCollection";
2197 asyncResp->res.jsonValue["@odata.context"] =
2198 "/redfish/v1/$metadata"
2199 "#VLanNetworkInterfaceCollection."
2200 "VLanNetworkInterfaceCollection";
2201 asyncResp->res.jsonValue["Name"] =
2202 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002203
Jason M. Billsf12894f2018-10-09 12:45:45 -07002204 nlohmann::json iface_array = nlohmann::json::array();
2205
2206 for (const std::string &iface_item : iface_list)
2207 {
2208 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2209 {
2210 iface_array.push_back(
2211 {{"@odata.id",
2212 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2213 rootInterfaceName + "/VLANs/" + iface_item}});
2214 }
2215 }
2216
Jason M. Billsf12894f2018-10-09 12:45:45 -07002217 asyncResp->res.jsonValue["Members@odata.count"] =
2218 iface_array.size();
2219 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2220 asyncResp->res.jsonValue["@odata.id"] =
2221 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2222 rootInterfaceName + "/VLANs";
2223 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002224 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002225
Ed Tanous1abe55e2018-09-05 08:30:59 -07002226 void doPost(crow::Response &res, const crow::Request &req,
2227 const std::vector<std::string> &params) override
2228 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002229 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002230 if (params.size() != 1)
2231 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002232 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002233 return;
2234 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002235 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002236 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002237 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2238 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002239 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002240 return;
2241 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002242 // Need both vlanId and vlanEnable to service this request
2243 if (!vlanId)
2244 {
2245 messages::propertyMissing(asyncResp->res, "VLANId");
2246 }
2247 if (!vlanEnable)
2248 {
2249 messages::propertyMissing(asyncResp->res, "VLANEnable");
2250 }
2251 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2252 {
2253 return;
2254 }
2255
Ed Tanous4a0cb852018-10-15 07:55:04 -07002256 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002257 auto callback = [asyncResp](const boost::system::error_code ec) {
2258 if (ec)
2259 {
2260 // TODO(ed) make more consistent error messages based on
2261 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002262 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002263 return;
2264 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002265 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002266 };
2267 crow::connections::systemBus->async_method_call(
2268 std::move(callback), "xyz.openbmc_project.Network",
2269 "/xyz/openbmc_project/network",
2270 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002271 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002272 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002273};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002274} // namespace redfish