blob: 79322100e01a6bf78b21a55a1ed9ef38b90c0c30 [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous1abe55e2018-09-05 08:30:59 -070018#include <boost/container/flat_map.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070019#include <boost/container/flat_set.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020020#include <dbus_singleton.hpp>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020021#include <error_messages.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020022#include <node.hpp>
Ed Tanousa24526d2018-12-10 15:17:59 -080023#include <optional>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020024#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080025#include <variant>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010029
30/**
31 * DBus types primitives for several generic DBus interfaces
32 * TODO(Pawel) consider move this to separate file into boost::dbus
33 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using PropertiesMapType = boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080035 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36 int32_t, uint32_t, int64_t, uint64_t, double>>;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010037
Ed Tanous4a0cb852018-10-15 07:55:04 -070038using GetManagedObjects = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039 sdbusplus::message::object_path,
Ed Tanous4a0cb852018-10-15 07:55:04 -070040 std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070041 std::string,
42 boost::container::flat_map<
Ed Tanous029573d2019-02-01 10:57:49 -080043 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
45 int32_t, uint32_t, int64_t, uint64_t, double,
46 std::vector<std::string>>>>>>>;
Ed Tanous4a0cb852018-10-15 07:55:04 -070047
48enum class LinkType
49{
50 Local,
51 Global
52};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010053
54/**
55 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010056 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070057struct IPv4AddressData
58{
59 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070060 std::string address;
61 std::string domain;
62 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 std::string netmask;
64 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070065 LinkType linktype;
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 bool operator<(const IPv4AddressData &obj) const
68 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070069 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
81 uint8_t prefixLength;
82
83 bool operator<(const IPv6AddressData &obj) const
84 {
85 return id < obj.id;
86 }
87};
88/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010089 * Structure for keeping basic single Ethernet Interface information
90 * available from DBus
91 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070092struct EthernetInterfaceData
93{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t speed;
95 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053096 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070097 std::string hostname;
98 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -050099 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700100 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500101 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -0800102 std::vector<std::string> nameservers;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800103 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100104};
105
Ed Tanous4a0cb852018-10-15 07:55:04 -0700106// Helper function that changes bits netmask notation (i.e. /24)
107// into full dot notation
108inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700110 uint32_t value = 0xffffffff << (32 - bits);
111 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
112 std::to_string((value >> 16) & 0xff) + "." +
113 std::to_string((value >> 8) & 0xff) + "." +
114 std::to_string(value & 0xff);
115 return netmask;
116}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100117
Ed Tanous4a0cb852018-10-15 07:55:04 -0700118inline std::string
119 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
120 bool isIPv4)
121{
122 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700124 return "Static";
125 }
126 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
127 {
128 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700130 return "IPv4LinkLocal";
131 }
132 else
133 {
134 return "LinkLocal";
135 }
136 }
137 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
138 {
139 if (isIPv4)
140 {
141 return "DHCP";
142 }
143 else
144 {
145 return "DHCPv6";
146 }
147 }
148 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
149 {
150 return "SLAAC";
151 }
152 return "";
153}
154
Ed Tanous4c9afe42019-05-03 16:59:57 -0700155inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700156 const GetManagedObjects &dbus_data,
157 EthernetInterfaceData &ethData)
158{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700159 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700160 for (const auto &objpath : dbus_data)
161 {
Ed Tanous029573d2019-02-01 10:57:49 -0800162 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700163 {
Ed Tanous029573d2019-02-01 10:57:49 -0800164 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700166 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700167 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700169 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700171 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700173 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800174 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700175 if (mac != nullptr)
176 {
177 ethData.mac_address = *mac;
178 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700180 }
181 }
182 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
183 {
184 for (const auto &propertyPair : ifacePair.second)
185 {
186 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800188 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800189 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700190 if (id != nullptr)
191 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500192 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700193 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700195 }
196 }
197 else if (ifacePair.first ==
198 "xyz.openbmc_project.Network.EthernetInterface")
199 {
200 for (const auto &propertyPair : ifacePair.second)
201 {
202 if (propertyPair.first == "AutoNeg")
203 {
204 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800205 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700206 if (auto_neg != nullptr)
207 {
208 ethData.auto_neg = *auto_neg;
209 }
210 }
211 else if (propertyPair.first == "Speed")
212 {
213 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800214 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700215 if (speed != nullptr)
216 {
217 ethData.speed = *speed;
218 }
219 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500220 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700221 {
Ed Tanous029573d2019-02-01 10:57:49 -0800222 const std::vector<std::string> *nameservers =
223 sdbusplus::message::variant_ns::get_if<
224 std::vector<std::string>>(
225 &propertyPair.second);
226 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700227 {
Ed Tanous029573d2019-02-01 10:57:49 -0800228 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700229 }
230 }
manojkiraneda2a133282019-02-19 13:09:43 +0530231 else if (propertyPair.first == "DHCPEnabled")
232 {
233 const bool *DHCPEnabled =
234 std::get_if<bool>(&propertyPair.second);
235 if (DHCPEnabled != nullptr)
236 {
237 ethData.DHCPEnabled = *DHCPEnabled;
238 }
239 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800240 else if (propertyPair.first == "DomainName")
241 {
242 const std::vector<std::string> *domainNames =
243 sdbusplus::message::variant_ns::get_if<
244 std::vector<std::string>>(
245 &propertyPair.second);
246 if (domainNames != nullptr)
247 {
248 ethData.domainnames = std::move(*domainNames);
249 }
250 }
Ed Tanous029573d2019-02-01 10:57:49 -0800251 }
252 }
253 }
254 // System configuration shows up in the global namespace, so no need
255 // to check eth number
256 if (ifacePair.first ==
257 "xyz.openbmc_project.Network.SystemConfiguration")
258 {
259 for (const auto &propertyPair : ifacePair.second)
260 {
261 if (propertyPair.first == "HostName")
262 {
263 const std::string *hostname =
264 sdbusplus::message::variant_ns::get_if<std::string>(
265 &propertyPair.second);
266 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700267 {
Ed Tanous029573d2019-02-01 10:57:49 -0800268 ethData.hostname = *hostname;
269 }
270 }
271 else if (propertyPair.first == "DefaultGateway")
272 {
273 const std::string *defaultGateway =
274 sdbusplus::message::variant_ns::get_if<std::string>(
275 &propertyPair.second);
276 if (defaultGateway != nullptr)
277 {
278 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700279 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500281 else if (propertyPair.first == "DefaultGateway6")
282 {
283 const std::string *defaultGateway6 =
284 sdbusplus::message::variant_ns::get_if<std::string>(
285 &propertyPair.second);
286 if (defaultGateway6 != nullptr)
287 {
288 ethData.ipv6_default_gateway = *defaultGateway6;
289 }
290 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 }
292 }
293 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700295 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700296}
297
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500298// Helper function that extracts data for single ethernet ipv6 address
299inline void extractIPV6Data(
300 const std::string &ethiface_id, const GetManagedObjects &dbus_data,
301 boost::container::flat_set<IPv6AddressData> &ipv6_config,
302 boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
303{
304 const std::string ipv6PathStart =
305 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
306
307 // Since there might be several IPv6 configurations aligned with
308 // single ethernet interface, loop over all of them
309 for (const auto &objpath : dbus_data)
310 {
311 // Check if proper pattern for object path appears
312 if (boost::starts_with(objpath.first.str, ipv6PathStart))
313 {
314 for (auto &interface : objpath.second)
315 {
316 if (interface.first == "xyz.openbmc_project.Network.IP")
317 {
318 // Instance IPv6AddressData structure, and set as
319 // appropriate
320 std::pair<
321 boost::container::flat_set<IPv6AddressData>::iterator,
322 bool>
323 it = ipv6_config.insert(
324 {objpath.first.str.substr(ipv6PathStart.size())});
325 IPv6AddressData &ipv6_address = *it.first;
326 for (auto &property : interface.second)
327 {
328 if (property.first == "Address")
329 {
330 const std::string *address =
331 std::get_if<std::string>(&property.second);
332 if (address != nullptr)
333 {
334 ipv6_address.address = *address;
335 }
336 }
337 else if (property.first == "Origin")
338 {
339 const std::string *origin =
340 std::get_if<std::string>(&property.second);
341 if (origin != nullptr)
342 {
343 ipv6_address.origin =
344 translateAddressOriginDbusToRedfish(*origin,
345 false);
346 }
347 }
348 else if (property.first == "PrefixLength")
349 {
350 const uint8_t *prefix =
351 std::get_if<uint8_t>(&property.second);
352 if (prefix != nullptr)
353 {
354 ipv6_address.prefixLength = *prefix;
355 }
356 }
357 else
358 {
359 BMCWEB_LOG_ERROR
360 << "Got extra property: " << property.first
361 << " on the " << objpath.first.str << " object";
362 }
363 }
364 if (ipv6_address.origin == "Static")
365 {
366 std::pair<boost::container::flat_set<
367 IPv6AddressData>::iterator,
368 bool>
369 iter = ipv6_static_config.insert(
370 {objpath.first.str.substr(
371 ipv6PathStart.size())});
372 IPv6AddressData &ipv6_static_address = *iter.first;
373
374 ipv6_static_address.address = ipv6_address.address;
375 ipv6_static_address.prefixLength =
376 ipv6_address.prefixLength;
377 }
378 }
379 }
380 }
381 }
382}
383
Ed Tanous4a0cb852018-10-15 07:55:04 -0700384// Helper function that extracts data for single ethernet ipv4 address
Ravi Tejad1d50812019-06-23 16:20:27 -0500385inline void extractIPData(
386 const std::string &ethiface_id, const GetManagedObjects &dbus_data,
387 boost::container::flat_set<IPv4AddressData> &ipv4_config,
388 boost::container::flat_set<IPv4AddressData> &ipv4_static_config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700389{
390 const std::string ipv4PathStart =
391 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
392
393 // Since there might be several IPv4 configurations aligned with
394 // single ethernet interface, loop over all of them
395 for (const auto &objpath : dbus_data)
396 {
397 // Check if proper pattern for object path appears
398 if (boost::starts_with(objpath.first.str, ipv4PathStart))
399 {
400 for (auto &interface : objpath.second)
401 {
402 if (interface.first == "xyz.openbmc_project.Network.IP")
403 {
404 // Instance IPv4AddressData structure, and set as
405 // appropriate
406 std::pair<
407 boost::container::flat_set<IPv4AddressData>::iterator,
408 bool>
409 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000410 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700411 IPv4AddressData &ipv4_address = *it.first;
412 for (auto &property : interface.second)
413 {
414 if (property.first == "Address")
415 {
416 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800417 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700418 if (address != nullptr)
419 {
420 ipv4_address.address = *address;
421 }
422 }
423 else if (property.first == "Gateway")
424 {
425 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800426 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700427 if (gateway != nullptr)
428 {
429 ipv4_address.gateway = *gateway;
430 }
431 }
432 else if (property.first == "Origin")
433 {
434 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800435 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700436 if (origin != nullptr)
437 {
438 ipv4_address.origin =
439 translateAddressOriginDbusToRedfish(*origin,
440 true);
441 }
442 }
443 else if (property.first == "PrefixLength")
444 {
445 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800446 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700447 if (mask != nullptr)
448 {
449 // convert it to the string
450 ipv4_address.netmask = getNetmask(*mask);
451 }
452 }
453 else
454 {
455 BMCWEB_LOG_ERROR
456 << "Got extra property: " << property.first
457 << " on the " << objpath.first.str << " object";
458 }
459 }
Ravi Tejad1d50812019-06-23 16:20:27 -0500460
461 if (ipv4_address.origin == "Static")
462 {
463 IPv4AddressData ipv4_static_address = {
464 objpath.first.str.substr(ipv4PathStart.size())};
465 ipv4_static_address.address = ipv4_address.address;
466 ipv4_static_address.gateway = ipv4_address.gateway;
467 ipv4_static_address.netmask = ipv4_address.netmask;
468 ipv4_static_config.emplace(ipv4_static_address);
469 }
470
Ed Tanous4a0cb852018-10-15 07:55:04 -0700471 // Check if given address is local, or global
472 ipv4_address.linktype =
473 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700474 ? LinkType::Local
475 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700476 }
477 }
478 }
479 }
480}
481
482/**
483 * @brief Sets given Id on the given VLAN interface through D-Bus
484 *
485 * @param[in] ifaceId Id of VLAN interface that should be modified
486 * @param[in] inputVlanId New ID of the VLAN
487 * @param[in] callback Function that will be called after the operation
488 *
489 * @return None.
490 */
491template <typename CallbackFunc>
492void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
493 CallbackFunc &&callback)
494{
495 crow::connections::systemBus->async_method_call(
496 callback, "xyz.openbmc_project.Network",
497 std::string("/xyz/openbmc_project/network/") + ifaceId,
498 "org.freedesktop.DBus.Properties", "Set",
499 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800500 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700501}
502
503/**
504 * @brief Helper function that verifies IP address to check if it is in
505 * proper format. If bits pointer is provided, also calculates active
506 * bit count for Subnet Mask.
507 *
508 * @param[in] ip IP that will be verified
509 * @param[out] bits Calculated mask in bits notation
510 *
511 * @return true in case of success, false otherwise
512 */
513inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
514 uint8_t *bits = nullptr)
515{
516 std::vector<std::string> bytesInMask;
517
518 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519
520 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700521 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700523 return false;
524 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525
Ed Tanous4a0cb852018-10-15 07:55:04 -0700526 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700528 *bits = 0;
529 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530
Ed Tanous4a0cb852018-10-15 07:55:04 -0700531 char *endPtr;
532 long previousValue = 255;
533 bool firstZeroInByteHit;
534 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700536 if (byte.empty())
537 {
538 return false;
539 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540
Ed Tanous4a0cb852018-10-15 07:55:04 -0700541 // Use strtol instead of stroi to avoid exceptions
542 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543
Ed Tanous4a0cb852018-10-15 07:55:04 -0700544 // endPtr should point to the end of the string, otherwise given string
545 // is not 100% number
546 if (*endPtr != '\0')
547 {
548 return false;
549 }
550
551 // Value should be contained in byte
552 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 {
554 return false;
555 }
556
557 if (bits != nullptr)
558 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700559 // Mask has to be continuous between bytes
560 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 {
562 return false;
563 }
564
Ed Tanous4a0cb852018-10-15 07:55:04 -0700565 // Mask has to be continuous inside bytes
566 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567
Ed Tanous4a0cb852018-10-15 07:55:04 -0700568 // Count bits
569 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700571 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700573 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700575 // Continuity not preserved
576 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 }
578 else
579 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700580 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 }
582 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 else
584 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700585 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700586 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700587 }
588 }
589
590 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 }
592
Ed Tanous4a0cb852018-10-15 07:55:04 -0700593 return true;
594}
595
596/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000597 * @brief Changes IPv4 address type property (Address, Gateway)
598 *
599 * @param[in] ifaceId Id of interface whose IP should be modified
600 * @param[in] ipIdx Index of IP in input array that should be modified
601 * @param[in] ipHash DBus Hash id of modified IP
602 * @param[in] name Name of field in JSON representation
603 * @param[in] newValue New value that should be written
604 * @param[io] asyncResp Response object that will be returned to client
605 *
606 * @return true if give IP is valid and has been sent do D-Bus, false
607 * otherwise
608 */
609inline void changeIPv4AddressProperty(
610 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
611 const std::string &name, const std::string &newValue,
612 const std::shared_ptr<AsyncResp> asyncResp)
613{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700614 auto callback =
615 [asyncResp, ipIdx, name{std::string(name)},
616 newValue{std::move(newValue)}](const boost::system::error_code ec) {
617 if (ec)
618 {
619 messages::internalError(asyncResp->res);
620 }
621 };
Ed Tanousb01bf292019-03-25 19:25:26 +0000622
623 crow::connections::systemBus->async_method_call(
624 std::move(callback), "xyz.openbmc_project.Network",
625 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
626 "org.freedesktop.DBus.Properties", "Set",
627 "xyz.openbmc_project.Network.IP", name,
628 std::variant<std::string>(newValue));
629}
630
631/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700632 * @brief Modifies SubnetMask for given IP
633 *
634 * @param[in] ifaceId Id of interface whose IP should be modified
635 * @param[in] ipIdx Index of IP in input array that should be
636 * modified
637 * @param[in] ipHash DBus Hash id of modified IP
Ed Tanous4a0cb852018-10-15 07:55:04 -0700638 * @param[in] newValue Mask as PrefixLength in bitcount
639 * @param[io] asyncResp Response object that will be returned to client
640 *
641 * @return None
642 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000643inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700644 const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700645 uint8_t &newValue,
646 std::shared_ptr<AsyncResp> asyncResp)
647{
Johnathan Mantey286b9112019-06-10 13:38:04 -0700648 auto callback = [asyncResp, ipIdx](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700649 if (ec)
650 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800651 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700652 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700653 };
654
655 crow::connections::systemBus->async_method_call(
656 std::move(callback), "xyz.openbmc_project.Network",
657 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
658 "org.freedesktop.DBus.Properties", "Set",
659 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800660 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700661}
662
663/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700664 * @brief Deletes given IPv4
665 *
666 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700667 * @param[in] ipHash DBus Hash id of IP that should be deleted
668 * @param[io] asyncResp Response object that will be returned to client
669 *
670 * @return None
671 */
672inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700673 const std::shared_ptr<AsyncResp> asyncResp)
674{
675 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700676 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 if (ec)
678 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800679 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100680 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700681 },
682 "xyz.openbmc_project.Network",
683 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
684 "xyz.openbmc_project.Object.Delete", "Delete");
685}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686
Ed Tanous4a0cb852018-10-15 07:55:04 -0700687/**
688 * @brief Creates IPv4 with given data
689 *
690 * @param[in] ifaceId Id of interface whose IP should be deleted
691 * @param[in] ipIdx Index of IP in input array that should be deleted
692 * @param[in] ipHash DBus Hash id of IP that should be deleted
693 * @param[io] asyncResp Response object that will be returned to client
694 *
695 * @return None
696 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000697inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
698 uint8_t subnetMask, const std::string &gateway,
699 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700700 std::shared_ptr<AsyncResp> asyncResp)
701{
Ed Tanous43b761d2019-02-13 20:10:56 -0800702 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700703 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800705 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 };
708
Ed Tanous4a0cb852018-10-15 07:55:04 -0700709 crow::connections::systemBus->async_method_call(
710 std::move(createIpHandler), "xyz.openbmc_project.Network",
711 "/xyz/openbmc_project/network/" + ifaceId,
712 "xyz.openbmc_project.Network.IP.Create", "IP",
713 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
714 gateway);
715}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500716
717/**
718 * @brief Deletes given IPv6
719 *
720 * @param[in] ifaceId Id of interface whose IP should be deleted
721 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500722 * @param[io] asyncResp Response object that will be returned to client
723 *
724 * @return None
725 */
726inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500727 const std::shared_ptr<AsyncResp> asyncResp)
728{
729 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700730 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500731 if (ec)
732 {
733 messages::internalError(asyncResp->res);
734 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500735 },
736 "xyz.openbmc_project.Network",
737 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
738 "xyz.openbmc_project.Object.Delete", "Delete");
739}
740
741/**
742 * @brief Creates IPv6 with given data
743 *
744 * @param[in] ifaceId Id of interface whose IP should be added
745 * @param[in] ipIdx Index of IP in input array that should be added
746 * @param[in] prefixLength Prefix length that needs to be added
747 * @param[in] address IP address that needs to be added
748 * @param[io] asyncResp Response object that will be returned to client
749 *
750 * @return None
751 */
752inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
753 uint8_t prefixLength, const std::string &address,
754 std::shared_ptr<AsyncResp> asyncResp)
755{
756 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
757 if (ec)
758 {
759 messages::internalError(asyncResp->res);
760 }
761 };
762 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
763 // does not have assosiated gateway property
764 crow::connections::systemBus->async_method_call(
765 std::move(createIpHandler), "xyz.openbmc_project.Network",
766 "/xyz/openbmc_project/network/" + ifaceId,
767 "xyz.openbmc_project.Network.IP.Create", "IP",
768 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
769 "");
770}
771
manojkiraneda2a133282019-02-19 13:09:43 +0530772using GetAllPropertiesType =
773 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
774
775inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
776{
777 auto getConfig = [asyncResp](const boost::system::error_code error_code,
778 const GetAllPropertiesType &dbus_data) {
779 if (error_code)
780 {
781 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
782 messages::internalError(asyncResp->res);
783 return;
784 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500785 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530786 for (const auto &property : dbus_data)
787 {
788 auto value =
789 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
790
791 if (value == nullptr)
792 {
793 continue;
794 }
795 if (property.first == "DNSEnabled")
796 {
797 DHCPConfigTypeJson["UseDNSServers"] = *value;
798 }
799 else if (property.first == "HostNameEnabled")
800 {
801 DHCPConfigTypeJson["UseDomainName"] = *value;
802 }
803 else if (property.first == "NTPEnabled")
804 {
805 DHCPConfigTypeJson["UseNTPServers"] = *value;
806 }
807 }
808 };
809 crow::connections::systemBus->async_method_call(
810 std::move(getConfig), "xyz.openbmc_project.Network",
811 "/xyz/openbmc_project/network/config/dhcp",
812 "org.freedesktop.DBus.Properties", "GetAll",
813 "xyz.openbmc_project.Network.DHCPConfiguration");
814}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815
Ed Tanous4a0cb852018-10-15 07:55:04 -0700816/**
817 * Function that retrieves all properties for given Ethernet Interface
818 * Object
819 * from EntityManager Network Manager
820 * @param ethiface_id a eth interface id to query on DBus
821 * @param callback a function that shall be called to convert Dbus output
822 * into JSON
823 */
824template <typename CallbackFunc>
825void getEthernetIfaceData(const std::string &ethiface_id,
826 CallbackFunc &&callback)
827{
828 crow::connections::systemBus->async_method_call(
829 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
830 const boost::system::error_code error_code,
831 const GetManagedObjects &resp) {
832 EthernetInterfaceData ethData{};
833 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejad1d50812019-06-23 16:20:27 -0500834 boost::container::flat_set<IPv4AddressData> ipv4StaticData;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500835 boost::container::flat_set<IPv6AddressData> ipv6Data;
836 boost::container::flat_set<IPv6AddressData> ipv6StaticData;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700837
838 if (error_code)
839 {
Ravi Tejad1d50812019-06-23 16:20:27 -0500840 callback(false, ethData, ipv4Data, ipv4StaticData, ipv6Data,
841 ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700842 return;
843 }
844
Ed Tanous4c9afe42019-05-03 16:59:57 -0700845 bool found =
846 extractEthernetInterfaceData(ethiface_id, resp, ethData);
847 if (!found)
848 {
Ravi Tejad1d50812019-06-23 16:20:27 -0500849 callback(false, ethData, ipv4Data, ipv4StaticData, ipv6Data,
850 ipv6StaticData);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700851 return;
852 }
853
Ravi Tejad1d50812019-06-23 16:20:27 -0500854 extractIPData(ethiface_id, resp, ipv4Data, ipv4StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700855 // Fix global GW
856 for (IPv4AddressData &ipv4 : ipv4Data)
857 {
Ravi Tejac6191412019-07-30 00:53:50 -0500858 if (((ipv4.linktype == LinkType::Global) &&
859 (ipv4.gateway == "0.0.0.0")) ||
860 (ipv4.origin == "DHCP"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700862 ipv4.gateway = ethData.default_gateway;
863 }
864 }
865
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500866 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700867 // Finally make a callback with usefull data
Ravi Tejad1d50812019-06-23 16:20:27 -0500868 callback(true, ethData, ipv4Data, ipv4StaticData, ipv6Data,
869 ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700870 },
871 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
872 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
873};
874
875/**
876 * Function that retrieves all Ethernet Interfaces available through Network
877 * Manager
878 * @param callback a function that shall be called to convert Dbus output
879 * into JSON.
880 */
881template <typename CallbackFunc>
882void getEthernetIfaceList(CallbackFunc &&callback)
883{
884 crow::connections::systemBus->async_method_call(
885 [callback{std::move(callback)}](
886 const boost::system::error_code error_code,
887 GetManagedObjects &resp) {
888 // Callback requires vector<string> to retrieve all available
889 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700890 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700891 iface_list.reserve(resp.size());
892 if (error_code)
893 {
894 callback(false, iface_list);
895 return;
896 }
897
898 // Iterate over all retrieved ObjectPaths.
899 for (const auto &objpath : resp)
900 {
901 // And all interfaces available for certain ObjectPath.
902 for (const auto &interface : objpath.second)
903 {
904 // If interface is
905 // xyz.openbmc_project.Network.EthernetInterface, this is
906 // what we're looking for.
907 if (interface.first ==
908 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700910 // Cut out everyting until last "/", ...
911 const std::string &iface_id = objpath.first.str;
912 std::size_t last_pos = iface_id.rfind("/");
913 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700915 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700916 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 }
918 }
919 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700920 }
921 // Finally make a callback with useful data
922 callback(true, iface_list);
923 },
924 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
925 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100926};
927
928/**
929 * EthernetCollection derived class for delivering Ethernet Collection Schema
930 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931class EthernetCollection : public Node
932{
933 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700934 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700936 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700938 entityPrivileges = {
939 {boost::beast::http::verb::get, {{"Login"}}},
940 {boost::beast::http::verb::head, {{"Login"}}},
941 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
942 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
943 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
944 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
945 }
946
947 private:
948 /**
949 * Functions triggers appropriate requests on DBus
950 */
951 void doGet(crow::Response &res, const crow::Request &req,
952 const std::vector<std::string> &params) override
953 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800954 res.jsonValue["@odata.type"] =
955 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
956 res.jsonValue["@odata.context"] =
957 "/redfish/v1/"
958 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
959 res.jsonValue["@odata.id"] =
960 "/redfish/v1/Managers/bmc/EthernetInterfaces";
961 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
962 res.jsonValue["Description"] =
963 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700964 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700965 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700966 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700967 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700968 [asyncResp](
969 const bool &success,
970 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700971 if (!success)
972 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700973 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700974 return;
975 }
976
Ed Tanous4c9afe42019-05-03 16:59:57 -0700977 nlohmann::json &iface_array =
978 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700979 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500980 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700981 for (const std::string &iface_item : iface_list)
982 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500983 std::size_t found = iface_item.find(tag);
984 if (found == std::string::npos)
985 {
986 iface_array.push_back(
987 {{"@odata.id",
988 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
989 iface_item}});
990 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700991 }
992
Ed Tanous4c9afe42019-05-03 16:59:57 -0700993 asyncResp->res.jsonValue["Members@odata.count"] =
994 iface_array.size();
995 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700996 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700997 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700998 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100999};
1000
1001/**
1002 * EthernetInterface derived class for delivering Ethernet Schema
1003 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004class EthernetInterface : public Node
1005{
1006 public:
1007 /*
1008 * Default Constructor
1009 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001010 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001012 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001013 std::string())
1014 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001015 entityPrivileges = {
1016 {boost::beast::http::verb::get, {{"Login"}}},
1017 {boost::beast::http::verb::head, {{"Login"}}},
1018 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1019 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1020 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1021 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001022 }
1023
Ed Tanous1abe55e2018-09-05 08:30:59 -07001024 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001025 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001026 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001027 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001028 asyncResp->res.jsonValue["HostName"] = hostname;
1029 crow::connections::systemBus->async_method_call(
1030 [asyncResp](const boost::system::error_code ec) {
1031 if (ec)
1032 {
1033 messages::internalError(asyncResp->res);
1034 }
1035 },
1036 "xyz.openbmc_project.Network",
1037 "/xyz/openbmc_project/network/config",
1038 "org.freedesktop.DBus.Properties", "Set",
1039 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001040 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001041 }
1042
Ratan Guptad5776652019-03-03 08:47:22 +05301043 void handleMACAddressPatch(const std::string &ifaceId,
1044 const std::string &macAddress,
1045 const std::shared_ptr<AsyncResp> &asyncResp)
1046 {
1047 crow::connections::systemBus->async_method_call(
1048 [asyncResp, macAddress](const boost::system::error_code ec) {
1049 if (ec)
1050 {
1051 messages::internalError(asyncResp->res);
1052 return;
1053 }
Ratan Guptad5776652019-03-03 08:47:22 +05301054 },
1055 "xyz.openbmc_project.Network",
1056 "/xyz/openbmc_project/network/" + ifaceId,
1057 "org.freedesktop.DBus.Properties", "Set",
1058 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1059 std::variant<std::string>(macAddress));
1060 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001061
Jennifer Leeda131a92019-04-24 15:13:55 -07001062 void setDHCPEnabled(const std::string &ifaceId,
1063 const std::string &propertyName, const bool &value,
1064 const std::shared_ptr<AsyncResp> asyncResp)
1065 {
1066 crow::connections::systemBus->async_method_call(
1067 [asyncResp](const boost::system::error_code ec) {
1068 if (ec)
1069 {
1070 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1071 messages::internalError(asyncResp->res);
1072 return;
1073 }
1074 },
1075 "xyz.openbmc_project.Network",
1076 "/xyz/openbmc_project/network/" + ifaceId,
1077 "org.freedesktop.DBus.Properties", "Set",
1078 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1079 std::variant<bool>{value});
1080 }
1081 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1082 const std::shared_ptr<AsyncResp> asyncResp)
1083 {
1084 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1085 crow::connections::systemBus->async_method_call(
1086 [asyncResp](const boost::system::error_code ec) {
1087 if (ec)
1088 {
1089 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1090 messages::internalError(asyncResp->res);
1091 return;
1092 }
1093 },
1094 "xyz.openbmc_project.Network",
1095 "/xyz/openbmc_project/network/config/dhcp",
1096 "org.freedesktop.DBus.Properties", "Set",
1097 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1098 std::variant<bool>{value});
1099 }
Ratan Guptad5776652019-03-03 08:47:22 +05301100
Jennifer Leeda131a92019-04-24 15:13:55 -07001101 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1102 const std::shared_ptr<AsyncResp> asyncResp)
1103 {
1104 std::optional<bool> dhcpEnabled;
1105 std::optional<bool> useDNSServers;
1106 std::optional<bool> useDomainName;
1107 std::optional<bool> useNTPServers;
1108
1109 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1110 dhcpEnabled, "UseDNSServers", useDNSServers,
1111 "UseDomainName", useDomainName,
1112 "UseNTPServers", useNTPServers))
1113 {
1114 return;
1115 }
1116
1117 if (dhcpEnabled)
1118 {
1119 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1120 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1121 }
1122
1123 if (useDNSServers)
1124 {
1125 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1126 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1127 }
1128
1129 if (useDomainName)
1130 {
1131 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1132 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1133 }
1134
1135 if (useNTPServers)
1136 {
1137 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1138 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1139 }
1140 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001141 void handleIPv4StaticPatch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301142 const std::string &ifaceId, nlohmann::json &input,
Ravi Tejad1d50812019-06-23 16:20:27 -05001143 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001144 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001145 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301146 if (!input.is_array())
1147 {
1148 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Ravi Tejad1d50812019-06-23 16:20:27 -05001149 "IPv4StaticAddresses");
Ratan Guptaf476acb2019-03-02 16:46:57 +05301150 return;
1151 }
1152
Ed Tanous4a0cb852018-10-15 07:55:04 -07001153 int entryIdx = 0;
1154 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
Ravi Tejad1d50812019-06-23 16:20:27 -05001155 ipv4StaticData.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001156 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001157 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001158 std::string pathString =
Ravi Tejad1d50812019-06-23 16:20:27 -05001159 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001160
Ratan Guptaf476acb2019-03-02 16:46:57 +05301161 if (thisJson.is_null())
1162 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001163 if (thisData != ipv4StaticData.end())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301164 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001165 deleteIPv4(ifaceId, thisData->id, asyncResp);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301166 thisData++;
1167 }
1168 else
1169 {
1170 messages::propertyValueFormatError(
1171 asyncResp->res, input.dump(), pathString);
1172 return;
1173 // TODO(ratagupt) Not sure about the property where value is
1174 // list and if unable to update one of the
1175 // list value then should we proceed further or
1176 // break there, would ask in the redfish forum
1177 // till then we stop processing the next list item.
1178 }
1179 entryIdx++;
1180 continue; // not an error as per the redfish spec.
1181 }
1182
Ratan Gupta9474b372019-03-01 15:13:37 +05301183 if (thisJson.empty())
1184 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001185 if (thisData != ipv4StaticData.end())
Ratan Gupta9474b372019-03-01 15:13:37 +05301186 {
1187 thisData++;
1188 }
1189 else
1190 {
1191 messages::propertyMissing(asyncResp->res,
1192 pathString + "/Address");
1193 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301194 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301195 // list and if unable to update one of the
1196 // list value then should we proceed further or
1197 // break there, would ask in the redfish forum
1198 // till then we stop processing the next list item.
1199 }
1200 entryIdx++;
1201 continue; // not an error as per the redfish spec.
1202 }
1203
Ed Tanous537174c2018-12-10 15:09:31 -08001204 std::optional<std::string> address;
Ed Tanous537174c2018-12-10 15:09:31 -08001205 std::optional<std::string> subnetMask;
1206 std::optional<std::string> gateway;
1207
1208 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
Johnathan Mantey7e27d832019-06-11 10:31:56 -07001209 address, "SubnetMask", subnetMask,
1210 "Gateway", gateway))
Ed Tanous537174c2018-12-10 15:09:31 -08001211 {
1212 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001213 }
1214
Ed Tanous537174c2018-12-10 15:09:31 -08001215 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 {
Ed Tanous537174c2018-12-10 15:09:31 -08001217 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001218 {
Ed Tanous537174c2018-12-10 15:09:31 -08001219 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001220 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001221 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001222 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001224
Ed Tanous537174c2018-12-10 15:09:31 -08001225 uint8_t prefixLength = 0;
1226 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001227 {
Ed Tanous537174c2018-12-10 15:09:31 -08001228 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001229 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001230 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001231 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001232 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001233 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001234 }
1235 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001236
Ed Tanous537174c2018-12-10 15:09:31 -08001237 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001238 {
Ed Tanous537174c2018-12-10 15:09:31 -08001239 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001240 {
Ed Tanous537174c2018-12-10 15:09:31 -08001241 messages::propertyValueFormatError(asyncResp->res, *gateway,
1242 pathString + "/Gateway");
1243 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001244 }
1245 }
1246
Ratan Guptaf476acb2019-03-02 16:46:57 +05301247 // if IP address exist then modify it.
Ravi Tejad1d50812019-06-23 16:20:27 -05001248 if (thisData != ipv4StaticData.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001249 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301250 // Apply changes
1251 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001252 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001253 auto callback =
1254 [asyncResp](const boost::system::error_code ec) {
1255 if (ec)
1256 {
1257 messages::internalError(asyncResp->res);
1258 return;
1259 }
1260 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301261
Ed Tanous4a0cb852018-10-15 07:55:04 -07001262 crow::connections::systemBus->async_method_call(
1263 std::move(callback), "xyz.openbmc_project.Network",
1264 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1265 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301266 "org.freedesktop.DBus.Properties", "Set",
1267 "xyz.openbmc_project.Network.IP", "Address",
1268 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001269 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301270
1271 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001272 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301273 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
Johnathan Mantey286b9112019-06-10 13:38:04 -07001274 thisData->id, prefixLength,
1275 asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001276 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301277
Ratan Guptaf476acb2019-03-02 16:46:57 +05301278 if (gateway)
1279 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001280 auto callback =
1281 [asyncResp](const boost::system::error_code ec) {
1282 if (ec)
1283 {
1284 messages::internalError(asyncResp->res);
1285 return;
1286 }
1287 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301288
1289 crow::connections::systemBus->async_method_call(
1290 std::move(callback), "xyz.openbmc_project.Network",
1291 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1292 thisData->id,
1293 "org.freedesktop.DBus.Properties", "Set",
1294 "xyz.openbmc_project.Network.IP", "Gateway",
1295 std::variant<std::string>(*gateway));
1296 }
1297
Ed Tanous4a0cb852018-10-15 07:55:04 -07001298 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001299 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001300 else
1301 {
1302 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001303 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001304 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001305 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001306 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001307 continue;
1308 }
1309
Ed Tanous537174c2018-12-10 15:09:31 -08001310 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001311 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001312 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001313 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001314 continue;
1315 }
1316
Ed Tanous537174c2018-12-10 15:09:31 -08001317 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001318 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001319 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001320 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001321 continue;
1322 }
1323
Ed Tanousb01bf292019-03-25 19:25:26 +00001324 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1325 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301326
Ravi Tejad1d50812019-06-23 16:20:27 -05001327 nlohmann::json &ipv4StaticAddressJson =
1328 asyncResp->res.jsonValue["IPv4StaticAddresses"][entryIdx];
1329 ipv4StaticAddressJson["Address"] = *address;
1330 ipv4StaticAddressJson["SubnetMask"] = *subnetMask;
1331 ipv4StaticAddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001332 }
1333 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001334 }
1335 }
1336
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001337 void handleStaticNameServersPatch(
1338 const std::string &ifaceId,
1339 const std::vector<std::string> &updatedStaticNameServers,
1340 const std::shared_ptr<AsyncResp> &asyncResp)
1341 {
1342 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001343 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001344 if (ec)
1345 {
1346 messages::internalError(asyncResp->res);
1347 return;
1348 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001349 },
1350 "xyz.openbmc_project.Network",
1351 "/xyz/openbmc_project/network/" + ifaceId,
1352 "org.freedesktop.DBus.Properties", "Set",
1353 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1354 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1355 }
1356
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001357 void handleIPv6StaticAddressesPatch(
1358 const std::string &ifaceId, nlohmann::json &input,
1359 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1360 const std::shared_ptr<AsyncResp> asyncResp)
1361 {
1362 if (!input.is_array())
1363 {
1364 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1365 "IPv6StaticAddresses");
1366 return;
1367 }
1368
1369 int entryIdx = 0;
1370 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1371 ipv6StaticData.begin();
1372 for (nlohmann::json &thisJson : input)
1373 {
1374 std::string pathString =
1375 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1376
1377 if (thisJson.is_null())
1378 {
1379 if (thisData != ipv6StaticData.end())
1380 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001381 deleteIPv6(ifaceId, thisData->id, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001382 thisData++;
1383 }
1384 else
1385 {
1386 messages::propertyValueFormatError(
1387 asyncResp->res, input.dump(), pathString);
1388 return;
1389 }
1390 entryIdx++;
1391 continue;
1392 }
1393
1394 if (thisJson.empty())
1395 {
1396 if (thisData != ipv6StaticData.end())
1397 {
1398 thisData++;
1399 }
1400 else
1401 {
1402 messages::propertyMissing(asyncResp->res,
1403 pathString + "/Address");
1404 return;
1405 }
1406 entryIdx++;
1407 continue;
1408 }
1409
1410 std::optional<std::string> address;
1411 std::optional<uint8_t> prefixLength;
1412
1413 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1414 address, "PrefixLength", prefixLength))
1415 {
1416 return;
1417 }
1418
1419 // if IP address exist then modify it.
1420 if (thisData != ipv6StaticData.end())
1421 {
1422 // Apply changes
1423 if (address)
1424 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001425 auto callback =
1426 [asyncResp](const boost::system::error_code ec) {
1427 if (ec)
1428 {
1429 messages::internalError(asyncResp->res);
1430 return;
1431 }
1432 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001433
1434 crow::connections::systemBus->async_method_call(
1435 std::move(callback), "xyz.openbmc_project.Network",
1436 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1437 thisData->id,
1438 "org.freedesktop.DBus.Properties", "Set",
1439 "xyz.openbmc_project.Network.IP", "Address",
1440 std::variant<std::string>(*address));
1441 }
1442
1443 if (prefixLength)
1444 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001445 auto callback =
1446 [asyncResp](const boost::system::error_code ec) {
1447 if (ec)
1448 {
1449 messages::internalError(asyncResp->res);
1450 return;
1451 }
1452 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001453
1454 crow::connections::systemBus->async_method_call(
1455 std::move(callback), "xyz.openbmc_project.Network",
1456 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1457 thisData->id,
1458 "org.freedesktop.DBus.Properties", "Set",
1459 "xyz.openbmc_project.Network.IP", "PrefixLength",
1460 std::variant<uint8_t>(*prefixLength));
1461 }
1462
1463 thisData++;
1464 }
1465 else
1466 {
1467 // Create IPv6 with provided data
1468
1469 if (!prefixLength)
1470 {
1471 messages::propertyMissing(asyncResp->res,
1472 pathString + "/PrefixLength");
1473 continue;
1474 }
1475
1476 if (!address)
1477 {
1478 messages::propertyMissing(asyncResp->res,
1479 pathString + "/Address");
1480 continue;
1481 }
1482
1483 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1484 asyncResp);
1485
1486 nlohmann::json &ipv6StaticAddressJson =
1487 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1488 ipv6StaticAddressJson["Address"] = *address;
1489 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1490 }
1491 entryIdx++;
1492 }
1493 }
1494
Ed Tanous0f74e642018-11-12 15:17:05 -08001495 void parseInterfaceData(
1496 nlohmann::json &json_response, const std::string &iface_id,
1497 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001498 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001499 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001500 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1501 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001502 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001503 json_response["Id"] = iface_id;
1504 json_response["@odata.id"] =
1505 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001506 json_response["InterfaceEnabled"] = true;
1507 if (ethData.speed == 0)
1508 {
1509 json_response["LinkStatus"] = "NoLink";
1510 json_response["Status"] = {
1511 {"Health", "OK"},
1512 {"State", "Disabled"},
1513 };
1514 }
1515 else
1516 {
1517 json_response["LinkStatus"] = "LinkUp";
1518 json_response["Status"] = {
1519 {"Health", "OK"},
1520 {"State", "Enabled"},
1521 };
1522 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001523 json_response["SpeedMbps"] = ethData.speed;
1524 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001525 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301526
Ed Tanous4a0cb852018-10-15 07:55:04 -07001527 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001529 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001530 if (!ethData.domainnames.empty())
1531 {
1532 json_response["FQDN"] =
1533 ethData.hostname + "." + ethData.domainnames[0];
1534 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001535 }
1536
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001537 json_response["VLANs"] = {
1538 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1539 iface_id + "/VLANs"}};
1540
Ed Tanous029573d2019-02-01 10:57:49 -08001541 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001542 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543
Ravi Tejad1d50812019-06-23 16:20:27 -05001544 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1545 ipv4_array = nlohmann::json::array();
1546 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001548
1549 std::string gatewayStr = ipv4_config.gateway;
1550 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001552 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001554
1555 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1556 {"SubnetMask", ipv4_config.netmask},
1557 {"Address", ipv4_config.address},
1558 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001560
1561 nlohmann::json &ipv4_static_array =
1562 json_response["IPv4StaticAddresses"];
1563 ipv4_static_array = nlohmann::json::array();
1564 for (auto &ipv4_static_config : ipv4StaticData)
1565 {
1566
1567 std::string gatewayStr = ipv4_static_config.gateway;
1568 if (gatewayStr.empty())
1569 {
1570 gatewayStr = "0.0.0.0";
1571 }
1572
1573 ipv4_static_array.push_back(
1574 {{"SubnetMask", ipv4_static_config.netmask},
1575 {"Address", ipv4_static_config.address},
1576 {"Gateway", gatewayStr}});
1577 }
1578
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001579 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001580
1581 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1582 ipv6_array = nlohmann::json::array();
1583 for (auto &ipv6_config : ipv6Data)
1584 {
1585 ipv6_array.push_back({{"Address", ipv6_config.address},
1586 {"PrefixLength", ipv6_config.prefixLength},
1587 {"AddressOrigin", ipv6_config.origin}});
1588 }
1589
1590 nlohmann::json &ipv6_static_array =
1591 json_response["IPv6StaticAddresses"];
1592 ipv6_static_array = nlohmann::json::array();
1593 for (auto &ipv6_static_config : ipv6StaticData)
1594 {
1595 ipv6_static_array.push_back(
1596 {{"Address", ipv6_static_config.address},
1597 {"PrefixLength", ipv6_static_config.prefixLength}});
1598 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001599 }
1600
1601 /**
1602 * Functions triggers appropriate requests on DBus
1603 */
1604 void doGet(crow::Response &res, const crow::Request &req,
1605 const std::vector<std::string> &params) override
1606 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001607 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001608 if (params.size() != 1)
1609 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001610 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001611 return;
1612 }
1613
Ed Tanous4a0cb852018-10-15 07:55:04 -07001614 getEthernetIfaceData(
1615 params[0],
1616 [this, asyncResp, iface_id{std::string(params[0])}](
1617 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001618 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001619 const boost::container::flat_set<IPv4AddressData>
1620 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001621 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1622 const boost::container::flat_set<IPv6AddressData>
1623 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001624 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001625 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 // TODO(Pawel)consider distinguish between non existing
1627 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001628 messages::resourceNotFound(asyncResp->res,
1629 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001630 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001631 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001632
1633 // because this has no dependence on the interface at this
1634 // point, it needs to be done after we know the interface
1635 // exists, not before.
1636 getDHCPConfigData(asyncResp);
1637
Ed Tanous0f74e642018-11-12 15:17:05 -08001638 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001639 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001640 asyncResp->res.jsonValue["@odata.context"] =
1641 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1642 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1643 asyncResp->res.jsonValue["Description"] =
1644 "Management Network Interface";
1645
1646 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001647 ipv4Data, ipv4StaticData, ipv6Data,
1648 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649 });
1650 }
1651
1652 void doPatch(crow::Response &res, const crow::Request &req,
1653 const std::vector<std::string> &params) override
1654 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001655 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656 if (params.size() != 1)
1657 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001658 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659 return;
1660 }
1661
Ed Tanous4a0cb852018-10-15 07:55:04 -07001662 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001663
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001664 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301665 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001666 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301667 std::optional<nlohmann::json> ipv4Addresses;
Ravi Tejad1d50812019-06-23 16:20:27 -05001668 std::optional<nlohmann::json> ipv4StaticAddresses;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301669 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001670 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001671 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001672 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001673 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001674
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001675 if (!json_util::readJson(
1676 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Ravi Tejad1d50812019-06-23 16:20:27 -05001677 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1678 macAddress, "StaticNameServers", staticNameServers,
1679 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1680 ipv6StaticAddresses, "NameServers", nameServers, "DHCPv4",
1681 dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 {
1683 return;
1684 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301685
Jennifer Leeda131a92019-04-24 15:13:55 -07001686 if (dhcpv4)
1687 {
1688 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1689 }
1690
Ed Tanous4a0cb852018-10-15 07:55:04 -07001691 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001692 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001693 getEthernetIfaceData(
1694 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001695 [this, asyncResp, iface_id, hostname = std::move(hostname),
1696 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001697 ipv4Addresses = std::move(ipv4Addresses),
Ravi Tejad1d50812019-06-23 16:20:27 -05001698 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001699 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001700 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001701 staticNameServers = std::move(staticNameServers),
1702 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001703 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001704 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001705 const boost::container::flat_set<IPv4AddressData>
1706 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001707 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1708 const boost::container::flat_set<IPv6AddressData>
1709 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 if (!success)
1711 {
1712 // ... otherwise return error
1713 // TODO(Pawel)consider distinguish between non existing
1714 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001715 messages::resourceNotFound(asyncResp->res,
1716 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717 return;
1718 }
1719
Ed Tanous0627a2c2018-11-29 17:09:23 -08001720 if (hostname)
1721 {
1722 handleHostnamePatch(*hostname, asyncResp);
1723 }
1724
Ratan Guptad5776652019-03-03 08:47:22 +05301725 if (macAddress)
1726 {
1727 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1728 }
1729
Ed Tanous0627a2c2018-11-29 17:09:23 -08001730 if (ipv4Addresses)
1731 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001732 messages::propertyNotWritable(asyncResp->res,
1733 "IPv4Addresses");
1734 }
1735
1736 if (ipv4StaticAddresses)
1737 {
Ed Tanous537174c2018-12-10 15:09:31 -08001738 // TODO(ed) for some reason the capture of ipv4Addresses
1739 // above is returning a const value, not a non-const value.
1740 // This doesn't really work for us, as we need to be able to
1741 // efficiently move out the intermedia nlohmann::json
1742 // objects. This makes a copy of the structure, and operates
1743 // on that, but could be done more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001744 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
1745 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4StaticData,
1746 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001747 }
1748
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001749 if (nameServers)
1750 {
1751 // Data.Permissions is read-only
1752 messages::propertyNotWritable(asyncResp->res,
1753 "NameServers");
1754 }
1755
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001756 if (staticNameServers)
1757 {
1758 handleStaticNameServersPatch(iface_id, *staticNameServers,
1759 asyncResp);
1760 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001761
1762 if (ipv6DefaultGateway)
1763 {
1764 messages::propertyNotWritable(asyncResp->res,
1765 "IPv6DefaultGateway");
1766 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001767
1768 if (ipv6StaticAddresses)
1769 {
1770 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1771 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1772 ipv6StaticData, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001773 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001774 });
1775 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001776};
1777
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001778/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001779 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1780 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001781 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782class VlanNetworkInterface : public Node
1783{
1784 public:
1785 /*
1786 * Default Constructor
1787 */
1788 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001789 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001790 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001791 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001792 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001794 entityPrivileges = {
1795 {boost::beast::http::verb::get, {{"Login"}}},
1796 {boost::beast::http::verb::head, {{"Login"}}},
1797 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1798 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1799 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1800 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001801 }
1802
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001804 void parseInterfaceData(
1805 nlohmann::json &json_response, const std::string &parent_iface_id,
1806 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001807 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001808 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001809 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1810 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001812 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001813 json_response["Id"] = iface_id;
1814 json_response["@odata.id"] =
1815 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1816 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817
Ed Tanous4a0cb852018-10-15 07:55:04 -07001818 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001819 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001820 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001821 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001822 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001823 }
1824
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001825 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 {
1827 if (!boost::starts_with(iface, parent + "_"))
1828 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001829 return false;
1830 }
1831 else
1832 {
1833 return true;
1834 }
1835 }
1836
1837 /**
1838 * Functions triggers appropriate requests on DBus
1839 */
1840 void doGet(crow::Response &res, const crow::Request &req,
1841 const std::vector<std::string> &params) override
1842 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001843 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1844 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001845 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1846 // Check if there is required param, truly entering this shall be
1847 // impossible.
1848 if (params.size() != 2)
1849 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001850 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001851 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001852 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001854
Ed Tanous4a0cb852018-10-15 07:55:04 -07001855 const std::string &parent_iface_id = params[0];
1856 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001857 res.jsonValue["@odata.type"] =
1858 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1859 res.jsonValue["@odata.context"] =
1860 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1861 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001862
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001863 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001864 {
1865 return;
1866 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001867
Ed Tanous1abe55e2018-09-05 08:30:59 -07001868 // Get single eth interface data, and call the below callback for JSON
1869 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001870 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001871 params[1],
1872 [this, asyncResp, parent_iface_id{std::string(params[0])},
1873 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001874 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001875 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001876 const boost::container::flat_set<IPv4AddressData>
1877 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001878 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1879 const boost::container::flat_set<IPv6AddressData>
1880 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001881 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001883 parseInterfaceData(asyncResp->res.jsonValue,
1884 parent_iface_id, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001885 ipv4Data, ipv4StaticData, ipv6Data,
1886 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001887 }
1888 else
1889 {
1890 // ... otherwise return error
1891 // TODO(Pawel)consider distinguish between non existing
1892 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001893 messages::resourceNotFound(
1894 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001896 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001897 }
1898
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899 void doPatch(crow::Response &res, const crow::Request &req,
1900 const std::vector<std::string> &params) override
1901 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001902 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001903 if (params.size() != 2)
1904 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001905 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001906 return;
1907 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001908
Ed Tanous1abe55e2018-09-05 08:30:59 -07001909 const std::string &parentIfaceId = params[0];
1910 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001911
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001912 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001913 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001914 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1915 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001916 return;
1917 }
1918
Ed Tanous0627a2c2018-11-29 17:09:23 -08001919 bool vlanEnable = false;
1920 uint64_t vlanId = 0;
1921
1922 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1923 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001924 {
1925 return;
1926 }
1927
1928 // Get single eth interface data, and call the below callback for JSON
1929 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001930 getEthernetIfaceData(
1931 params[1],
1932 [this, asyncResp, parentIfaceId{std::string(params[0])},
1933 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1934 const bool &success, const EthernetInterfaceData &ethData,
1935 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001936 const boost::container::flat_set<IPv4AddressData>
1937 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001938 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1939 const boost::container::flat_set<IPv6AddressData>
1940 &ipv6StaticData) {
1941 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001942 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001943 auto callback =
1944 [asyncResp](const boost::system::error_code ec) {
1945 if (ec)
1946 {
1947 messages::internalError(asyncResp->res);
1948 }
1949 };
1950
1951 if (vlanEnable == true)
1952 {
1953 crow::connections::systemBus->async_method_call(
1954 std::move(callback), "xyz.openbmc_project.Network",
1955 "/xyz/openbmc_project/network/" + ifaceId,
1956 "org.freedesktop.DBus.Properties", "Set",
1957 "xyz.openbmc_project.Network.VLAN", "Id",
1958 std::variant<uint32_t>(vlanId));
1959 }
1960 else
1961 {
1962 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1963 "vlan interface";
1964 crow::connections::systemBus->async_method_call(
1965 std::move(callback), "xyz.openbmc_project.Network",
1966 std::string("/xyz/openbmc_project/network/") +
1967 ifaceId,
1968 "xyz.openbmc_project.Object.Delete", "Delete");
1969 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001970 }
1971 else
1972 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001973 // TODO(Pawel)consider distinguish between non existing
1974 // object, and other errors
1975 messages::resourceNotFound(
1976 asyncResp->res, "VLAN Network Interface", ifaceId);
1977 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001978 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001979 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001980 }
1981
1982 void doDelete(crow::Response &res, const crow::Request &req,
1983 const std::vector<std::string> &params) override
1984 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001985 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001986 if (params.size() != 2)
1987 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001988 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001989 return;
1990 }
1991
1992 const std::string &parentIfaceId = params[0];
1993 const std::string &ifaceId = params[1];
1994
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001995 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001996 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001997 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1998 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001999 return;
2000 }
2001
2002 // Get single eth interface data, and call the below callback for JSON
2003 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002004 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002005 params[1],
2006 [this, asyncResp, parentIfaceId{std::string(params[0])},
2007 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002008 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002009 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05002010 const boost::container::flat_set<IPv4AddressData>
2011 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002012 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2013 const boost::container::flat_set<IPv6AddressData>
2014 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002015 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002016 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002017 auto callback =
2018 [asyncResp](const boost::system::error_code ec) {
2019 if (ec)
2020 {
2021 messages::internalError(asyncResp->res);
2022 }
2023 };
2024 crow::connections::systemBus->async_method_call(
2025 std::move(callback), "xyz.openbmc_project.Network",
2026 std::string("/xyz/openbmc_project/network/") + ifaceId,
2027 "xyz.openbmc_project.Object.Delete", "Delete");
2028 }
2029 else
2030 {
2031 // ... otherwise return error
2032 // TODO(Pawel)consider distinguish between non existing
2033 // object, and other errors
2034 messages::resourceNotFound(
2035 asyncResp->res, "VLAN Network Interface", ifaceId);
2036 }
2037 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002038 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002039};
2040
2041/**
2042 * VlanNetworkInterfaceCollection derived class for delivering
2043 * VLANNetworkInterface Collection Schema
2044 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002045class VlanNetworkInterfaceCollection : public Node
2046{
2047 public:
2048 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002049 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002050 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2051 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002052 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002053 entityPrivileges = {
2054 {boost::beast::http::verb::get, {{"Login"}}},
2055 {boost::beast::http::verb::head, {{"Login"}}},
2056 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2057 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2058 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2059 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002060 }
2061
Ed Tanous1abe55e2018-09-05 08:30:59 -07002062 private:
2063 /**
2064 * Functions triggers appropriate requests on DBus
2065 */
2066 void doGet(crow::Response &res, const crow::Request &req,
2067 const std::vector<std::string> &params) override
2068 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002069 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002070 if (params.size() != 1)
2071 {
2072 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002073 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002074 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002075 }
2076
Ed Tanous4a0cb852018-10-15 07:55:04 -07002077 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002078
Ed Tanous4a0cb852018-10-15 07:55:04 -07002079 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002080 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002081 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002082 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002083 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002084 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002085 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002086 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002087 messages::internalError(asyncResp->res);
2088 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002089 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002090
2091 if (iface_list.find(rootInterfaceName) == iface_list.end())
2092 {
2093 messages::resourceNotFound(asyncResp->res,
2094 "VLanNetworkInterfaceCollection",
2095 rootInterfaceName);
2096 return;
2097 }
2098
Ed Tanous0f74e642018-11-12 15:17:05 -08002099 asyncResp->res.jsonValue["@odata.type"] =
2100 "#VLanNetworkInterfaceCollection."
2101 "VLanNetworkInterfaceCollection";
2102 asyncResp->res.jsonValue["@odata.context"] =
2103 "/redfish/v1/$metadata"
2104 "#VLanNetworkInterfaceCollection."
2105 "VLanNetworkInterfaceCollection";
2106 asyncResp->res.jsonValue["Name"] =
2107 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002108
Jason M. Billsf12894f2018-10-09 12:45:45 -07002109 nlohmann::json iface_array = nlohmann::json::array();
2110
2111 for (const std::string &iface_item : iface_list)
2112 {
2113 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2114 {
2115 iface_array.push_back(
2116 {{"@odata.id",
2117 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2118 rootInterfaceName + "/VLANs/" + iface_item}});
2119 }
2120 }
2121
Jason M. Billsf12894f2018-10-09 12:45:45 -07002122 asyncResp->res.jsonValue["Members@odata.count"] =
2123 iface_array.size();
2124 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2125 asyncResp->res.jsonValue["@odata.id"] =
2126 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2127 rootInterfaceName + "/VLANs";
2128 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002129 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002130
Ed Tanous1abe55e2018-09-05 08:30:59 -07002131 void doPost(crow::Response &res, const crow::Request &req,
2132 const std::vector<std::string> &params) override
2133 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002134 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002135 if (params.size() != 1)
2136 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002137 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002138 return;
2139 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002140 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002141 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002142 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2143 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002144 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002145 return;
2146 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002147 // Need both vlanId and vlanEnable to service this request
2148 if (!vlanId)
2149 {
2150 messages::propertyMissing(asyncResp->res, "VLANId");
2151 }
2152 if (!vlanEnable)
2153 {
2154 messages::propertyMissing(asyncResp->res, "VLANEnable");
2155 }
2156 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2157 {
2158 return;
2159 }
2160
Ed Tanous4a0cb852018-10-15 07:55:04 -07002161 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002162 auto callback = [asyncResp](const boost::system::error_code ec) {
2163 if (ec)
2164 {
2165 // TODO(ed) make more consistent error messages based on
2166 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002167 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002168 return;
2169 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002170 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002171 };
2172 crow::connections::systemBus->async_method_call(
2173 std::move(callback), "xyz.openbmc_project.Network",
2174 "/xyz/openbmc_project/network",
2175 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002176 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002177 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002178};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002179} // namespace redfish