blob: 17b953b8eebd79c40caf8bbf3cabdc84752393f2 [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;
Manojkiran Eda95f86462019-08-07 15:07:54 +05301542
1543 if (!ethData.DHCPEnabled)
1544 {
1545 json_response["StaticNameServers"] = ethData.nameservers;
1546 }
1547 else
1548 {
1549 json_response["StaticNameServers"] = {};
1550 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551
Ravi Tejad1d50812019-06-23 16:20:27 -05001552 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1553 ipv4_array = nlohmann::json::array();
1554 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001556
1557 std::string gatewayStr = ipv4_config.gateway;
1558 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001560 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001562
1563 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1564 {"SubnetMask", ipv4_config.netmask},
1565 {"Address", ipv4_config.address},
1566 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001568
1569 nlohmann::json &ipv4_static_array =
1570 json_response["IPv4StaticAddresses"];
1571 ipv4_static_array = nlohmann::json::array();
1572 for (auto &ipv4_static_config : ipv4StaticData)
1573 {
1574
1575 std::string gatewayStr = ipv4_static_config.gateway;
1576 if (gatewayStr.empty())
1577 {
1578 gatewayStr = "0.0.0.0";
1579 }
1580
1581 ipv4_static_array.push_back(
1582 {{"SubnetMask", ipv4_static_config.netmask},
1583 {"Address", ipv4_static_config.address},
1584 {"Gateway", gatewayStr}});
1585 }
1586
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001587 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001588
1589 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1590 ipv6_array = nlohmann::json::array();
1591 for (auto &ipv6_config : ipv6Data)
1592 {
1593 ipv6_array.push_back({{"Address", ipv6_config.address},
1594 {"PrefixLength", ipv6_config.prefixLength},
1595 {"AddressOrigin", ipv6_config.origin}});
1596 }
1597
1598 nlohmann::json &ipv6_static_array =
1599 json_response["IPv6StaticAddresses"];
1600 ipv6_static_array = nlohmann::json::array();
1601 for (auto &ipv6_static_config : ipv6StaticData)
1602 {
1603 ipv6_static_array.push_back(
1604 {{"Address", ipv6_static_config.address},
1605 {"PrefixLength", ipv6_static_config.prefixLength}});
1606 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001607 }
1608
1609 /**
1610 * Functions triggers appropriate requests on DBus
1611 */
1612 void doGet(crow::Response &res, const crow::Request &req,
1613 const std::vector<std::string> &params) override
1614 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001615 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001616 if (params.size() != 1)
1617 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001618 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001619 return;
1620 }
1621
Ed Tanous4a0cb852018-10-15 07:55:04 -07001622 getEthernetIfaceData(
1623 params[0],
1624 [this, asyncResp, iface_id{std::string(params[0])}](
1625 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001626 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001627 const boost::container::flat_set<IPv4AddressData>
1628 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001629 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1630 const boost::container::flat_set<IPv6AddressData>
1631 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001632 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634 // TODO(Pawel)consider distinguish between non existing
1635 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001636 messages::resourceNotFound(asyncResp->res,
1637 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001638 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001639 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001640
1641 // because this has no dependence on the interface at this
1642 // point, it needs to be done after we know the interface
1643 // exists, not before.
1644 getDHCPConfigData(asyncResp);
1645
Ed Tanous0f74e642018-11-12 15:17:05 -08001646 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001647 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001648 asyncResp->res.jsonValue["@odata.context"] =
1649 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1650 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1651 asyncResp->res.jsonValue["Description"] =
1652 "Management Network Interface";
1653
1654 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001655 ipv4Data, ipv4StaticData, ipv6Data,
1656 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001657 });
1658 }
1659
1660 void doPatch(crow::Response &res, const crow::Request &req,
1661 const std::vector<std::string> &params) override
1662 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001663 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001664 if (params.size() != 1)
1665 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001666 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667 return;
1668 }
1669
Ed Tanous4a0cb852018-10-15 07:55:04 -07001670 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001671
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001672 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301673 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001674 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301675 std::optional<nlohmann::json> ipv4Addresses;
Ravi Tejad1d50812019-06-23 16:20:27 -05001676 std::optional<nlohmann::json> ipv4StaticAddresses;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301677 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001678 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001679 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001680 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001681 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001682
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001683 if (!json_util::readJson(
1684 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Ravi Tejad1d50812019-06-23 16:20:27 -05001685 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1686 macAddress, "StaticNameServers", staticNameServers,
1687 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1688 ipv6StaticAddresses, "NameServers", nameServers, "DHCPv4",
1689 dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001690 {
1691 return;
1692 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301693
Jennifer Leeda131a92019-04-24 15:13:55 -07001694 if (dhcpv4)
1695 {
1696 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1697 }
1698
Ed Tanous4a0cb852018-10-15 07:55:04 -07001699 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001701 getEthernetIfaceData(
1702 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001703 [this, asyncResp, iface_id, hostname = std::move(hostname),
1704 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001705 ipv4Addresses = std::move(ipv4Addresses),
Ravi Tejad1d50812019-06-23 16:20:27 -05001706 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001707 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001708 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001709 staticNameServers = std::move(staticNameServers),
1710 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001711 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001712 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001713 const boost::container::flat_set<IPv4AddressData>
1714 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001715 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1716 const boost::container::flat_set<IPv6AddressData>
1717 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001718 if (!success)
1719 {
1720 // ... otherwise return error
1721 // TODO(Pawel)consider distinguish between non existing
1722 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001723 messages::resourceNotFound(asyncResp->res,
1724 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001725 return;
1726 }
1727
Ed Tanous0627a2c2018-11-29 17:09:23 -08001728 if (hostname)
1729 {
1730 handleHostnamePatch(*hostname, asyncResp);
1731 }
1732
Ratan Guptad5776652019-03-03 08:47:22 +05301733 if (macAddress)
1734 {
1735 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1736 }
1737
Ed Tanous0627a2c2018-11-29 17:09:23 -08001738 if (ipv4Addresses)
1739 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001740 messages::propertyNotWritable(asyncResp->res,
1741 "IPv4Addresses");
1742 }
1743
1744 if (ipv4StaticAddresses)
1745 {
Ed Tanous537174c2018-12-10 15:09:31 -08001746 // TODO(ed) for some reason the capture of ipv4Addresses
1747 // above is returning a const value, not a non-const value.
1748 // This doesn't really work for us, as we need to be able to
1749 // efficiently move out the intermedia nlohmann::json
1750 // objects. This makes a copy of the structure, and operates
1751 // on that, but could be done more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001752 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
1753 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4StaticData,
1754 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001755 }
1756
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001757 if (nameServers)
1758 {
1759 // Data.Permissions is read-only
1760 messages::propertyNotWritable(asyncResp->res,
1761 "NameServers");
1762 }
1763
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001764 if (staticNameServers)
1765 {
1766 handleStaticNameServersPatch(iface_id, *staticNameServers,
1767 asyncResp);
1768 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001769
1770 if (ipv6DefaultGateway)
1771 {
1772 messages::propertyNotWritable(asyncResp->res,
1773 "IPv6DefaultGateway");
1774 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001775
1776 if (ipv6StaticAddresses)
1777 {
1778 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1779 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1780 ipv6StaticData, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001781 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782 });
1783 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001784};
1785
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001786/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001787 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1788 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001789 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001790class VlanNetworkInterface : public Node
1791{
1792 public:
1793 /*
1794 * Default Constructor
1795 */
1796 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001797 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001798 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001799 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001800 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 entityPrivileges = {
1803 {boost::beast::http::verb::get, {{"Login"}}},
1804 {boost::beast::http::verb::head, {{"Login"}}},
1805 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1806 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1807 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1808 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001809 }
1810
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001812 void parseInterfaceData(
1813 nlohmann::json &json_response, const std::string &parent_iface_id,
1814 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001815 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001816 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001817 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1818 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001821 json_response["Id"] = iface_id;
1822 json_response["@odata.id"] =
1823 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1824 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825
Ed Tanous4a0cb852018-10-15 07:55:04 -07001826 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001827 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001828 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001829 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001830 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001831 }
1832
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001833 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 {
1835 if (!boost::starts_with(iface, parent + "_"))
1836 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 return false;
1838 }
1839 else
1840 {
1841 return true;
1842 }
1843 }
1844
1845 /**
1846 * Functions triggers appropriate requests on DBus
1847 */
1848 void doGet(crow::Response &res, const crow::Request &req,
1849 const std::vector<std::string> &params) override
1850 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001851 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1852 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1854 // Check if there is required param, truly entering this shall be
1855 // impossible.
1856 if (params.size() != 2)
1857 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001858 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001860 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001862
Ed Tanous4a0cb852018-10-15 07:55:04 -07001863 const std::string &parent_iface_id = params[0];
1864 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001865 res.jsonValue["@odata.type"] =
1866 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1867 res.jsonValue["@odata.context"] =
1868 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1869 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001870
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001871 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001872 {
1873 return;
1874 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001875
Ed Tanous1abe55e2018-09-05 08:30:59 -07001876 // Get single eth interface data, and call the below callback for JSON
1877 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001878 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001879 params[1],
1880 [this, asyncResp, parent_iface_id{std::string(params[0])},
1881 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001882 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001883 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001884 const boost::container::flat_set<IPv4AddressData>
1885 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001886 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1887 const boost::container::flat_set<IPv6AddressData>
1888 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001889 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001890 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001891 parseInterfaceData(asyncResp->res.jsonValue,
1892 parent_iface_id, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001893 ipv4Data, ipv4StaticData, ipv6Data,
1894 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 }
1896 else
1897 {
1898 // ... otherwise return error
1899 // TODO(Pawel)consider distinguish between non existing
1900 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001901 messages::resourceNotFound(
1902 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001903 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001904 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001905 }
1906
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 void doPatch(crow::Response &res, const crow::Request &req,
1908 const std::vector<std::string> &params) override
1909 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001910 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001911 if (params.size() != 2)
1912 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001913 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001914 return;
1915 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001916
Ed Tanous1abe55e2018-09-05 08:30:59 -07001917 const std::string &parentIfaceId = params[0];
1918 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001919
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001920 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001922 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1923 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001924 return;
1925 }
1926
Ed Tanous0627a2c2018-11-29 17:09:23 -08001927 bool vlanEnable = false;
1928 uint64_t vlanId = 0;
1929
1930 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1931 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001932 {
1933 return;
1934 }
1935
1936 // Get single eth interface data, and call the below callback for JSON
1937 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001938 getEthernetIfaceData(
1939 params[1],
1940 [this, asyncResp, parentIfaceId{std::string(params[0])},
1941 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1942 const bool &success, const EthernetInterfaceData &ethData,
1943 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001944 const boost::container::flat_set<IPv4AddressData>
1945 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001946 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1947 const boost::container::flat_set<IPv6AddressData>
1948 &ipv6StaticData) {
1949 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001950 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001951 auto callback =
1952 [asyncResp](const boost::system::error_code ec) {
1953 if (ec)
1954 {
1955 messages::internalError(asyncResp->res);
1956 }
1957 };
1958
1959 if (vlanEnable == true)
1960 {
1961 crow::connections::systemBus->async_method_call(
1962 std::move(callback), "xyz.openbmc_project.Network",
1963 "/xyz/openbmc_project/network/" + ifaceId,
1964 "org.freedesktop.DBus.Properties", "Set",
1965 "xyz.openbmc_project.Network.VLAN", "Id",
1966 std::variant<uint32_t>(vlanId));
1967 }
1968 else
1969 {
1970 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1971 "vlan interface";
1972 crow::connections::systemBus->async_method_call(
1973 std::move(callback), "xyz.openbmc_project.Network",
1974 std::string("/xyz/openbmc_project/network/") +
1975 ifaceId,
1976 "xyz.openbmc_project.Object.Delete", "Delete");
1977 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001978 }
1979 else
1980 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001981 // TODO(Pawel)consider distinguish between non existing
1982 // object, and other errors
1983 messages::resourceNotFound(
1984 asyncResp->res, "VLAN Network Interface", ifaceId);
1985 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001986 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001987 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001988 }
1989
1990 void doDelete(crow::Response &res, const crow::Request &req,
1991 const std::vector<std::string> &params) override
1992 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001993 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001994 if (params.size() != 2)
1995 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001996 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997 return;
1998 }
1999
2000 const std::string &parentIfaceId = params[0];
2001 const std::string &ifaceId = params[1];
2002
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002003 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002004 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002005 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2006 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002007 return;
2008 }
2009
2010 // Get single eth interface data, and call the below callback for JSON
2011 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002012 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002013 params[1],
2014 [this, asyncResp, parentIfaceId{std::string(params[0])},
2015 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002016 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002017 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05002018 const boost::container::flat_set<IPv4AddressData>
2019 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002020 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2021 const boost::container::flat_set<IPv6AddressData>
2022 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002023 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002024 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002025 auto callback =
2026 [asyncResp](const boost::system::error_code ec) {
2027 if (ec)
2028 {
2029 messages::internalError(asyncResp->res);
2030 }
2031 };
2032 crow::connections::systemBus->async_method_call(
2033 std::move(callback), "xyz.openbmc_project.Network",
2034 std::string("/xyz/openbmc_project/network/") + ifaceId,
2035 "xyz.openbmc_project.Object.Delete", "Delete");
2036 }
2037 else
2038 {
2039 // ... otherwise return error
2040 // TODO(Pawel)consider distinguish between non existing
2041 // object, and other errors
2042 messages::resourceNotFound(
2043 asyncResp->res, "VLAN Network Interface", ifaceId);
2044 }
2045 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002046 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002047};
2048
2049/**
2050 * VlanNetworkInterfaceCollection derived class for delivering
2051 * VLANNetworkInterface Collection Schema
2052 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002053class VlanNetworkInterfaceCollection : public Node
2054{
2055 public:
2056 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002057 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002058 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2059 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002060 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002061 entityPrivileges = {
2062 {boost::beast::http::verb::get, {{"Login"}}},
2063 {boost::beast::http::verb::head, {{"Login"}}},
2064 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2065 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2066 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2067 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002068 }
2069
Ed Tanous1abe55e2018-09-05 08:30:59 -07002070 private:
2071 /**
2072 * Functions triggers appropriate requests on DBus
2073 */
2074 void doGet(crow::Response &res, const crow::Request &req,
2075 const std::vector<std::string> &params) override
2076 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002077 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002078 if (params.size() != 1)
2079 {
2080 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002081 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002082 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002083 }
2084
Ed Tanous4a0cb852018-10-15 07:55:04 -07002085 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002086
Ed Tanous4a0cb852018-10-15 07:55:04 -07002087 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002089 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002090 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002091 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002092 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002093 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002094 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002095 messages::internalError(asyncResp->res);
2096 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002097 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002098
2099 if (iface_list.find(rootInterfaceName) == iface_list.end())
2100 {
2101 messages::resourceNotFound(asyncResp->res,
2102 "VLanNetworkInterfaceCollection",
2103 rootInterfaceName);
2104 return;
2105 }
2106
Ed Tanous0f74e642018-11-12 15:17:05 -08002107 asyncResp->res.jsonValue["@odata.type"] =
2108 "#VLanNetworkInterfaceCollection."
2109 "VLanNetworkInterfaceCollection";
2110 asyncResp->res.jsonValue["@odata.context"] =
2111 "/redfish/v1/$metadata"
2112 "#VLanNetworkInterfaceCollection."
2113 "VLanNetworkInterfaceCollection";
2114 asyncResp->res.jsonValue["Name"] =
2115 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002116
Jason M. Billsf12894f2018-10-09 12:45:45 -07002117 nlohmann::json iface_array = nlohmann::json::array();
2118
2119 for (const std::string &iface_item : iface_list)
2120 {
2121 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2122 {
2123 iface_array.push_back(
2124 {{"@odata.id",
2125 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2126 rootInterfaceName + "/VLANs/" + iface_item}});
2127 }
2128 }
2129
Jason M. Billsf12894f2018-10-09 12:45:45 -07002130 asyncResp->res.jsonValue["Members@odata.count"] =
2131 iface_array.size();
2132 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2133 asyncResp->res.jsonValue["@odata.id"] =
2134 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2135 rootInterfaceName + "/VLANs";
2136 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002137 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002138
Ed Tanous1abe55e2018-09-05 08:30:59 -07002139 void doPost(crow::Response &res, const crow::Request &req,
2140 const std::vector<std::string> &params) override
2141 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002142 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002143 if (params.size() != 1)
2144 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002145 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002146 return;
2147 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002148 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002149 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002150 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2151 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002152 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002153 return;
2154 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002155 // Need both vlanId and vlanEnable to service this request
2156 if (!vlanId)
2157 {
2158 messages::propertyMissing(asyncResp->res, "VLANId");
2159 }
2160 if (!vlanEnable)
2161 {
2162 messages::propertyMissing(asyncResp->res, "VLANEnable");
2163 }
2164 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2165 {
2166 return;
2167 }
2168
Ed Tanous4a0cb852018-10-15 07:55:04 -07002169 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002170 auto callback = [asyncResp](const boost::system::error_code ec) {
2171 if (ec)
2172 {
2173 // TODO(ed) make more consistent error messages based on
2174 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002175 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002176 return;
2177 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002178 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002179 };
2180 crow::connections::systemBus->async_method_call(
2181 std::move(callback), "xyz.openbmc_project.Network",
2182 "/xyz/openbmc_project/network",
2183 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002184 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002185 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002186};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002187} // namespace redfish