blob: 266705286c97e557c61c03a55e5c3ae4bbfaeabd [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 {
858 if ((ipv4.linktype == LinkType::Global) &&
859 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700861 ipv4.gateway = ethData.default_gateway;
862 }
863 }
864
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500865 extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700866 // Finally make a callback with usefull data
Ravi Tejad1d50812019-06-23 16:20:27 -0500867 callback(true, ethData, ipv4Data, ipv4StaticData, ipv6Data,
868 ipv6StaticData);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700869 },
870 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
871 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
872};
873
874/**
875 * Function that retrieves all Ethernet Interfaces available through Network
876 * Manager
877 * @param callback a function that shall be called to convert Dbus output
878 * into JSON.
879 */
880template <typename CallbackFunc>
881void getEthernetIfaceList(CallbackFunc &&callback)
882{
883 crow::connections::systemBus->async_method_call(
884 [callback{std::move(callback)}](
885 const boost::system::error_code error_code,
886 GetManagedObjects &resp) {
887 // Callback requires vector<string> to retrieve all available
888 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700889 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700890 iface_list.reserve(resp.size());
891 if (error_code)
892 {
893 callback(false, iface_list);
894 return;
895 }
896
897 // Iterate over all retrieved ObjectPaths.
898 for (const auto &objpath : resp)
899 {
900 // And all interfaces available for certain ObjectPath.
901 for (const auto &interface : objpath.second)
902 {
903 // If interface is
904 // xyz.openbmc_project.Network.EthernetInterface, this is
905 // what we're looking for.
906 if (interface.first ==
907 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700908 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700909 // Cut out everyting until last "/", ...
910 const std::string &iface_id = objpath.first.str;
911 std::size_t last_pos = iface_id.rfind("/");
912 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700914 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700915 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 }
917 }
918 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700919 }
920 // Finally make a callback with useful data
921 callback(true, iface_list);
922 },
923 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
924 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100925};
926
927/**
928 * EthernetCollection derived class for delivering Ethernet Collection Schema
929 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930class EthernetCollection : public Node
931{
932 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700933 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700935 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 entityPrivileges = {
938 {boost::beast::http::verb::get, {{"Login"}}},
939 {boost::beast::http::verb::head, {{"Login"}}},
940 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
941 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
942 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
943 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
944 }
945
946 private:
947 /**
948 * Functions triggers appropriate requests on DBus
949 */
950 void doGet(crow::Response &res, const crow::Request &req,
951 const std::vector<std::string> &params) override
952 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800953 res.jsonValue["@odata.type"] =
954 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
955 res.jsonValue["@odata.context"] =
956 "/redfish/v1/"
957 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
958 res.jsonValue["@odata.id"] =
959 "/redfish/v1/Managers/bmc/EthernetInterfaces";
960 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
961 res.jsonValue["Description"] =
962 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700963 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700964 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700966 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700967 [asyncResp](
968 const bool &success,
969 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700970 if (!success)
971 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700972 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700973 return;
974 }
975
Ed Tanous4c9afe42019-05-03 16:59:57 -0700976 nlohmann::json &iface_array =
977 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700978 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500979 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700980 for (const std::string &iface_item : iface_list)
981 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500982 std::size_t found = iface_item.find(tag);
983 if (found == std::string::npos)
984 {
985 iface_array.push_back(
986 {{"@odata.id",
987 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
988 iface_item}});
989 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700990 }
991
Ed Tanous4c9afe42019-05-03 16:59:57 -0700992 asyncResp->res.jsonValue["Members@odata.count"] =
993 iface_array.size();
994 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700995 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700996 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700997 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100998};
999
1000/**
1001 * EthernetInterface derived class for delivering Ethernet Schema
1002 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001003class EthernetInterface : public Node
1004{
1005 public:
1006 /*
1007 * Default Constructor
1008 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001009 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001011 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 std::string())
1013 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 entityPrivileges = {
1015 {boost::beast::http::verb::get, {{"Login"}}},
1016 {boost::beast::http::verb::head, {{"Login"}}},
1017 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1018 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1019 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1020 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001021 }
1022
Ed Tanous1abe55e2018-09-05 08:30:59 -07001023 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001024 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001025 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001026 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001027 asyncResp->res.jsonValue["HostName"] = hostname;
1028 crow::connections::systemBus->async_method_call(
1029 [asyncResp](const boost::system::error_code ec) {
1030 if (ec)
1031 {
1032 messages::internalError(asyncResp->res);
1033 }
1034 },
1035 "xyz.openbmc_project.Network",
1036 "/xyz/openbmc_project/network/config",
1037 "org.freedesktop.DBus.Properties", "Set",
1038 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001039 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001040 }
1041
Ratan Guptad5776652019-03-03 08:47:22 +05301042 void handleMACAddressPatch(const std::string &ifaceId,
1043 const std::string &macAddress,
1044 const std::shared_ptr<AsyncResp> &asyncResp)
1045 {
1046 crow::connections::systemBus->async_method_call(
1047 [asyncResp, macAddress](const boost::system::error_code ec) {
1048 if (ec)
1049 {
1050 messages::internalError(asyncResp->res);
1051 return;
1052 }
Ratan Guptad5776652019-03-03 08:47:22 +05301053 },
1054 "xyz.openbmc_project.Network",
1055 "/xyz/openbmc_project/network/" + ifaceId,
1056 "org.freedesktop.DBus.Properties", "Set",
1057 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1058 std::variant<std::string>(macAddress));
1059 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001060
Jennifer Leeda131a92019-04-24 15:13:55 -07001061 void setDHCPEnabled(const std::string &ifaceId,
1062 const std::string &propertyName, const bool &value,
1063 const std::shared_ptr<AsyncResp> asyncResp)
1064 {
1065 crow::connections::systemBus->async_method_call(
1066 [asyncResp](const boost::system::error_code ec) {
1067 if (ec)
1068 {
1069 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1070 messages::internalError(asyncResp->res);
1071 return;
1072 }
1073 },
1074 "xyz.openbmc_project.Network",
1075 "/xyz/openbmc_project/network/" + ifaceId,
1076 "org.freedesktop.DBus.Properties", "Set",
1077 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1078 std::variant<bool>{value});
1079 }
1080 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1081 const std::shared_ptr<AsyncResp> asyncResp)
1082 {
1083 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1084 crow::connections::systemBus->async_method_call(
1085 [asyncResp](const boost::system::error_code ec) {
1086 if (ec)
1087 {
1088 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1089 messages::internalError(asyncResp->res);
1090 return;
1091 }
1092 },
1093 "xyz.openbmc_project.Network",
1094 "/xyz/openbmc_project/network/config/dhcp",
1095 "org.freedesktop.DBus.Properties", "Set",
1096 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1097 std::variant<bool>{value});
1098 }
Ratan Guptad5776652019-03-03 08:47:22 +05301099
Jennifer Leeda131a92019-04-24 15:13:55 -07001100 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1101 const std::shared_ptr<AsyncResp> asyncResp)
1102 {
1103 std::optional<bool> dhcpEnabled;
1104 std::optional<bool> useDNSServers;
1105 std::optional<bool> useDomainName;
1106 std::optional<bool> useNTPServers;
1107
1108 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1109 dhcpEnabled, "UseDNSServers", useDNSServers,
1110 "UseDomainName", useDomainName,
1111 "UseNTPServers", useNTPServers))
1112 {
1113 return;
1114 }
1115
1116 if (dhcpEnabled)
1117 {
1118 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1119 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1120 }
1121
1122 if (useDNSServers)
1123 {
1124 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1125 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1126 }
1127
1128 if (useDomainName)
1129 {
1130 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1131 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1132 }
1133
1134 if (useNTPServers)
1135 {
1136 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1137 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1138 }
1139 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001140 void handleIPv4StaticPatch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301141 const std::string &ifaceId, nlohmann::json &input,
Ravi Tejad1d50812019-06-23 16:20:27 -05001142 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001143 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001144 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301145 if (!input.is_array())
1146 {
1147 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Ravi Tejad1d50812019-06-23 16:20:27 -05001148 "IPv4StaticAddresses");
Ratan Guptaf476acb2019-03-02 16:46:57 +05301149 return;
1150 }
1151
Ed Tanous4a0cb852018-10-15 07:55:04 -07001152 int entryIdx = 0;
1153 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
Ravi Tejad1d50812019-06-23 16:20:27 -05001154 ipv4StaticData.begin();
Ed Tanous537174c2018-12-10 15:09:31 -08001155 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001156 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001157 std::string pathString =
Ravi Tejad1d50812019-06-23 16:20:27 -05001158 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001159
Ratan Guptaf476acb2019-03-02 16:46:57 +05301160 if (thisJson.is_null())
1161 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001162 if (thisData != ipv4StaticData.end())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301163 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001164 deleteIPv4(ifaceId, thisData->id, asyncResp);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301165 thisData++;
1166 }
1167 else
1168 {
1169 messages::propertyValueFormatError(
1170 asyncResp->res, input.dump(), pathString);
1171 return;
1172 // TODO(ratagupt) Not sure about the property where value is
1173 // list and if unable to update one of the
1174 // list value then should we proceed further or
1175 // break there, would ask in the redfish forum
1176 // till then we stop processing the next list item.
1177 }
1178 entryIdx++;
1179 continue; // not an error as per the redfish spec.
1180 }
1181
Ratan Gupta9474b372019-03-01 15:13:37 +05301182 if (thisJson.empty())
1183 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001184 if (thisData != ipv4StaticData.end())
Ratan Gupta9474b372019-03-01 15:13:37 +05301185 {
1186 thisData++;
1187 }
1188 else
1189 {
1190 messages::propertyMissing(asyncResp->res,
1191 pathString + "/Address");
1192 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301193 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +05301194 // list and if unable to update one of the
1195 // list value then should we proceed further or
1196 // break there, would ask in the redfish forum
1197 // till then we stop processing the next list item.
1198 }
1199 entryIdx++;
1200 continue; // not an error as per the redfish spec.
1201 }
1202
Ed Tanous537174c2018-12-10 15:09:31 -08001203 std::optional<std::string> address;
Ed Tanous537174c2018-12-10 15:09:31 -08001204 std::optional<std::string> subnetMask;
1205 std::optional<std::string> gateway;
1206
1207 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
Johnathan Mantey7e27d832019-06-11 10:31:56 -07001208 address, "SubnetMask", subnetMask,
1209 "Gateway", gateway))
Ed Tanous537174c2018-12-10 15:09:31 -08001210 {
1211 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001212 }
1213
Ed Tanous537174c2018-12-10 15:09:31 -08001214 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001215 {
Ed Tanous537174c2018-12-10 15:09:31 -08001216 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001217 {
Ed Tanous537174c2018-12-10 15:09:31 -08001218 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001219 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001220 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001221 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001222 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001223
Ed Tanous537174c2018-12-10 15:09:31 -08001224 uint8_t prefixLength = 0;
1225 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001226 {
Ed Tanous537174c2018-12-10 15:09:31 -08001227 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001228 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001229 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001230 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001231 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001232 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001233 }
1234 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001235
Ed Tanous537174c2018-12-10 15:09:31 -08001236 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001237 {
Ed Tanous537174c2018-12-10 15:09:31 -08001238 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001239 {
Ed Tanous537174c2018-12-10 15:09:31 -08001240 messages::propertyValueFormatError(asyncResp->res, *gateway,
1241 pathString + "/Gateway");
1242 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001243 }
1244 }
1245
Ratan Guptaf476acb2019-03-02 16:46:57 +05301246 // if IP address exist then modify it.
Ravi Tejad1d50812019-06-23 16:20:27 -05001247 if (thisData != ipv4StaticData.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301249 // Apply changes
1250 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001251 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001252 auto callback =
1253 [asyncResp](const boost::system::error_code ec) {
1254 if (ec)
1255 {
1256 messages::internalError(asyncResp->res);
1257 return;
1258 }
1259 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301260
Ed Tanous4a0cb852018-10-15 07:55:04 -07001261 crow::connections::systemBus->async_method_call(
1262 std::move(callback), "xyz.openbmc_project.Network",
1263 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1264 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301265 "org.freedesktop.DBus.Properties", "Set",
1266 "xyz.openbmc_project.Network.IP", "Address",
1267 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001268 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301269
1270 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001271 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301272 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
Johnathan Mantey286b9112019-06-10 13:38:04 -07001273 thisData->id, prefixLength,
1274 asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001275 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301276
Ratan Guptaf476acb2019-03-02 16:46:57 +05301277 if (gateway)
1278 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001279 auto callback =
1280 [asyncResp](const boost::system::error_code ec) {
1281 if (ec)
1282 {
1283 messages::internalError(asyncResp->res);
1284 return;
1285 }
1286 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301287
1288 crow::connections::systemBus->async_method_call(
1289 std::move(callback), "xyz.openbmc_project.Network",
1290 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1291 thisData->id,
1292 "org.freedesktop.DBus.Properties", "Set",
1293 "xyz.openbmc_project.Network.IP", "Gateway",
1294 std::variant<std::string>(*gateway));
1295 }
1296
Ed Tanous4a0cb852018-10-15 07:55:04 -07001297 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001299 else
1300 {
1301 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001302 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001303 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001304 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001305 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001306 continue;
1307 }
1308
Ed Tanous537174c2018-12-10 15:09:31 -08001309 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001310 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001311 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001312 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001313 continue;
1314 }
1315
Ed Tanous537174c2018-12-10 15:09:31 -08001316 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001317 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001318 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001319 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001320 continue;
1321 }
1322
Ed Tanousb01bf292019-03-25 19:25:26 +00001323 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1324 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301325
Ravi Tejad1d50812019-06-23 16:20:27 -05001326 nlohmann::json &ipv4StaticAddressJson =
1327 asyncResp->res.jsonValue["IPv4StaticAddresses"][entryIdx];
1328 ipv4StaticAddressJson["Address"] = *address;
1329 ipv4StaticAddressJson["SubnetMask"] = *subnetMask;
1330 ipv4StaticAddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001331 }
1332 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 }
1334 }
1335
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001336 void handleStaticNameServersPatch(
1337 const std::string &ifaceId,
1338 const std::vector<std::string> &updatedStaticNameServers,
1339 const std::shared_ptr<AsyncResp> &asyncResp)
1340 {
1341 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001342 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001343 if (ec)
1344 {
1345 messages::internalError(asyncResp->res);
1346 return;
1347 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001348 },
1349 "xyz.openbmc_project.Network",
1350 "/xyz/openbmc_project/network/" + ifaceId,
1351 "org.freedesktop.DBus.Properties", "Set",
1352 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1353 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1354 }
1355
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001356 void handleIPv6StaticAddressesPatch(
1357 const std::string &ifaceId, nlohmann::json &input,
1358 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1359 const std::shared_ptr<AsyncResp> asyncResp)
1360 {
1361 if (!input.is_array())
1362 {
1363 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1364 "IPv6StaticAddresses");
1365 return;
1366 }
1367
1368 int entryIdx = 0;
1369 boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1370 ipv6StaticData.begin();
1371 for (nlohmann::json &thisJson : input)
1372 {
1373 std::string pathString =
1374 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1375
1376 if (thisJson.is_null())
1377 {
1378 if (thisData != ipv6StaticData.end())
1379 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001380 deleteIPv6(ifaceId, thisData->id, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001381 thisData++;
1382 }
1383 else
1384 {
1385 messages::propertyValueFormatError(
1386 asyncResp->res, input.dump(), pathString);
1387 return;
1388 }
1389 entryIdx++;
1390 continue;
1391 }
1392
1393 if (thisJson.empty())
1394 {
1395 if (thisData != ipv6StaticData.end())
1396 {
1397 thisData++;
1398 }
1399 else
1400 {
1401 messages::propertyMissing(asyncResp->res,
1402 pathString + "/Address");
1403 return;
1404 }
1405 entryIdx++;
1406 continue;
1407 }
1408
1409 std::optional<std::string> address;
1410 std::optional<uint8_t> prefixLength;
1411
1412 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1413 address, "PrefixLength", prefixLength))
1414 {
1415 return;
1416 }
1417
1418 // if IP address exist then modify it.
1419 if (thisData != ipv6StaticData.end())
1420 {
1421 // Apply changes
1422 if (address)
1423 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001424 auto callback =
1425 [asyncResp](const boost::system::error_code ec) {
1426 if (ec)
1427 {
1428 messages::internalError(asyncResp->res);
1429 return;
1430 }
1431 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001432
1433 crow::connections::systemBus->async_method_call(
1434 std::move(callback), "xyz.openbmc_project.Network",
1435 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1436 thisData->id,
1437 "org.freedesktop.DBus.Properties", "Set",
1438 "xyz.openbmc_project.Network.IP", "Address",
1439 std::variant<std::string>(*address));
1440 }
1441
1442 if (prefixLength)
1443 {
Johnathan Mantey286b9112019-06-10 13:38:04 -07001444 auto callback =
1445 [asyncResp](const boost::system::error_code ec) {
1446 if (ec)
1447 {
1448 messages::internalError(asyncResp->res);
1449 return;
1450 }
1451 };
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001452
1453 crow::connections::systemBus->async_method_call(
1454 std::move(callback), "xyz.openbmc_project.Network",
1455 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1456 thisData->id,
1457 "org.freedesktop.DBus.Properties", "Set",
1458 "xyz.openbmc_project.Network.IP", "PrefixLength",
1459 std::variant<uint8_t>(*prefixLength));
1460 }
1461
1462 thisData++;
1463 }
1464 else
1465 {
1466 // Create IPv6 with provided data
1467
1468 if (!prefixLength)
1469 {
1470 messages::propertyMissing(asyncResp->res,
1471 pathString + "/PrefixLength");
1472 continue;
1473 }
1474
1475 if (!address)
1476 {
1477 messages::propertyMissing(asyncResp->res,
1478 pathString + "/Address");
1479 continue;
1480 }
1481
1482 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1483 asyncResp);
1484
1485 nlohmann::json &ipv6StaticAddressJson =
1486 asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1487 ipv6StaticAddressJson["Address"] = *address;
1488 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1489 }
1490 entryIdx++;
1491 }
1492 }
1493
Ed Tanous0f74e642018-11-12 15:17:05 -08001494 void parseInterfaceData(
1495 nlohmann::json &json_response, const std::string &iface_id,
1496 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001497 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001498 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001499 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1500 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001501 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001502 json_response["Id"] = iface_id;
1503 json_response["@odata.id"] =
1504 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001505 json_response["InterfaceEnabled"] = true;
1506 if (ethData.speed == 0)
1507 {
1508 json_response["LinkStatus"] = "NoLink";
1509 json_response["Status"] = {
1510 {"Health", "OK"},
1511 {"State", "Disabled"},
1512 };
1513 }
1514 else
1515 {
1516 json_response["LinkStatus"] = "LinkUp";
1517 json_response["Status"] = {
1518 {"Health", "OK"},
1519 {"State", "Enabled"},
1520 };
1521 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001522 json_response["SpeedMbps"] = ethData.speed;
1523 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001524 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301525
Ed Tanous4a0cb852018-10-15 07:55:04 -07001526 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001528 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001529 if (!ethData.domainnames.empty())
1530 {
1531 json_response["FQDN"] =
1532 ethData.hostname + "." + ethData.domainnames[0];
1533 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001534 }
1535
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001536 json_response["VLANs"] = {
1537 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1538 iface_id + "/VLANs"}};
1539
Ed Tanous029573d2019-02-01 10:57:49 -08001540 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001541 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001542
Ravi Tejad1d50812019-06-23 16:20:27 -05001543 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1544 ipv4_array = nlohmann::json::array();
1545 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001546 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001547
1548 std::string gatewayStr = ipv4_config.gateway;
1549 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001550 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001551 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001553
1554 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1555 {"SubnetMask", ipv4_config.netmask},
1556 {"Address", ipv4_config.address},
1557 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001558 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001559
1560 nlohmann::json &ipv4_static_array =
1561 json_response["IPv4StaticAddresses"];
1562 ipv4_static_array = nlohmann::json::array();
1563 for (auto &ipv4_static_config : ipv4StaticData)
1564 {
1565
1566 std::string gatewayStr = ipv4_static_config.gateway;
1567 if (gatewayStr.empty())
1568 {
1569 gatewayStr = "0.0.0.0";
1570 }
1571
1572 ipv4_static_array.push_back(
1573 {{"SubnetMask", ipv4_static_config.netmask},
1574 {"Address", ipv4_static_config.address},
1575 {"Gateway", gatewayStr}});
1576 }
1577
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001578 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001579
1580 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1581 ipv6_array = nlohmann::json::array();
1582 for (auto &ipv6_config : ipv6Data)
1583 {
1584 ipv6_array.push_back({{"Address", ipv6_config.address},
1585 {"PrefixLength", ipv6_config.prefixLength},
1586 {"AddressOrigin", ipv6_config.origin}});
1587 }
1588
1589 nlohmann::json &ipv6_static_array =
1590 json_response["IPv6StaticAddresses"];
1591 ipv6_static_array = nlohmann::json::array();
1592 for (auto &ipv6_static_config : ipv6StaticData)
1593 {
1594 ipv6_static_array.push_back(
1595 {{"Address", ipv6_static_config.address},
1596 {"PrefixLength", ipv6_static_config.prefixLength}});
1597 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001598 }
1599
1600 /**
1601 * Functions triggers appropriate requests on DBus
1602 */
1603 void doGet(crow::Response &res, const crow::Request &req,
1604 const std::vector<std::string> &params) override
1605 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001606 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001607 if (params.size() != 1)
1608 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001609 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610 return;
1611 }
1612
Ed Tanous4a0cb852018-10-15 07:55:04 -07001613 getEthernetIfaceData(
1614 params[0],
1615 [this, asyncResp, iface_id{std::string(params[0])}](
1616 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001617 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001618 const boost::container::flat_set<IPv4AddressData>
1619 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001620 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1621 const boost::container::flat_set<IPv6AddressData>
1622 &ipv6StaticData) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001623 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001624 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001625 // TODO(Pawel)consider distinguish between non existing
1626 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001627 messages::resourceNotFound(asyncResp->res,
1628 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001629 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001630 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001631
1632 // because this has no dependence on the interface at this
1633 // point, it needs to be done after we know the interface
1634 // exists, not before.
1635 getDHCPConfigData(asyncResp);
1636
Ed Tanous0f74e642018-11-12 15:17:05 -08001637 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001638 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001639 asyncResp->res.jsonValue["@odata.context"] =
1640 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1641 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1642 asyncResp->res.jsonValue["Description"] =
1643 "Management Network Interface";
1644
1645 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001646 ipv4Data, ipv4StaticData, ipv6Data,
1647 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001648 });
1649 }
1650
1651 void doPatch(crow::Response &res, const crow::Request &req,
1652 const std::vector<std::string> &params) override
1653 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001654 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001655 if (params.size() != 1)
1656 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001657 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001658 return;
1659 }
1660
Ed Tanous4a0cb852018-10-15 07:55:04 -07001661 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001662
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001663 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301664 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001665 std::optional<std::string> ipv6DefaultGateway;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301666 std::optional<nlohmann::json> ipv4Addresses;
Ravi Tejad1d50812019-06-23 16:20:27 -05001667 std::optional<nlohmann::json> ipv4StaticAddresses;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301668 std::optional<nlohmann::json> ipv6Addresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001669 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001670 std::optional<std::vector<std::string>> staticNameServers;
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001671 std::optional<std::vector<std::string>> nameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001672 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001673
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001674 if (!json_util::readJson(
1675 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
Ravi Tejad1d50812019-06-23 16:20:27 -05001676 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1677 macAddress, "StaticNameServers", staticNameServers,
1678 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1679 ipv6StaticAddresses, "NameServers", nameServers, "DHCPv4",
1680 dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001681 {
1682 return;
1683 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301684
Jennifer Leeda131a92019-04-24 15:13:55 -07001685 if (dhcpv4)
1686 {
1687 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1688 }
1689
Ed Tanous4a0cb852018-10-15 07:55:04 -07001690 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001691 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001692 getEthernetIfaceData(
1693 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001694 [this, asyncResp, iface_id, hostname = std::move(hostname),
1695 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001696 ipv4Addresses = std::move(ipv4Addresses),
Ravi Tejad1d50812019-06-23 16:20:27 -05001697 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001698 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001699 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001700 staticNameServers = std::move(staticNameServers),
1701 nameServers = std::move(nameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001702 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001703 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001704 const boost::container::flat_set<IPv4AddressData>
1705 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001706 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1707 const boost::container::flat_set<IPv6AddressData>
1708 &ipv6StaticData) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 if (!success)
1710 {
1711 // ... otherwise return error
1712 // TODO(Pawel)consider distinguish between non existing
1713 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001714 messages::resourceNotFound(asyncResp->res,
1715 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 return;
1717 }
1718
Ed Tanous0627a2c2018-11-29 17:09:23 -08001719 if (hostname)
1720 {
1721 handleHostnamePatch(*hostname, asyncResp);
1722 }
1723
Ratan Guptad5776652019-03-03 08:47:22 +05301724 if (macAddress)
1725 {
1726 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1727 }
1728
Ed Tanous0627a2c2018-11-29 17:09:23 -08001729 if (ipv4Addresses)
1730 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001731 messages::propertyNotWritable(asyncResp->res,
1732 "IPv4Addresses");
1733 }
1734
1735 if (ipv4StaticAddresses)
1736 {
Ed Tanous537174c2018-12-10 15:09:31 -08001737 // TODO(ed) for some reason the capture of ipv4Addresses
1738 // above is returning a const value, not a non-const value.
1739 // This doesn't really work for us, as we need to be able to
1740 // efficiently move out the intermedia nlohmann::json
1741 // objects. This makes a copy of the structure, and operates
1742 // on that, but could be done more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001743 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
1744 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4StaticData,
1745 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001746 }
1747
RAJESWARAN THILLAIGOVINDAN5112e9b2019-03-06 03:10:24 -06001748 if (nameServers)
1749 {
1750 // Data.Permissions is read-only
1751 messages::propertyNotWritable(asyncResp->res,
1752 "NameServers");
1753 }
1754
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001755 if (staticNameServers)
1756 {
1757 handleStaticNameServersPatch(iface_id, *staticNameServers,
1758 asyncResp);
1759 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001760
1761 if (ipv6DefaultGateway)
1762 {
1763 messages::propertyNotWritable(asyncResp->res,
1764 "IPv6DefaultGateway");
1765 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001766
1767 if (ipv6StaticAddresses)
1768 {
1769 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1770 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1771 ipv6StaticData, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001772 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001773 });
1774 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001775};
1776
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001777/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001778 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1779 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001780 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001781class VlanNetworkInterface : public Node
1782{
1783 public:
1784 /*
1785 * Default Constructor
1786 */
1787 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001788 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001789 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001790 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001791 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001792 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 entityPrivileges = {
1794 {boost::beast::http::verb::get, {{"Login"}}},
1795 {boost::beast::http::verb::head, {{"Login"}}},
1796 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1797 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1798 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1799 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001800 }
1801
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001803 void parseInterfaceData(
1804 nlohmann::json &json_response, const std::string &parent_iface_id,
1805 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001806 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001807 const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001808 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1809 const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001812 json_response["Id"] = iface_id;
1813 json_response["@odata.id"] =
1814 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1815 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001816
Ed Tanous4a0cb852018-10-15 07:55:04 -07001817 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001818 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001819 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001820 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001821 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001822 }
1823
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001824 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 {
1826 if (!boost::starts_with(iface, parent + "_"))
1827 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001828 return false;
1829 }
1830 else
1831 {
1832 return true;
1833 }
1834 }
1835
1836 /**
1837 * Functions triggers appropriate requests on DBus
1838 */
1839 void doGet(crow::Response &res, const crow::Request &req,
1840 const std::vector<std::string> &params) override
1841 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001842 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1843 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1845 // Check if there is required param, truly entering this shall be
1846 // impossible.
1847 if (params.size() != 2)
1848 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001849 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001851 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001852 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001853
Ed Tanous4a0cb852018-10-15 07:55:04 -07001854 const std::string &parent_iface_id = params[0];
1855 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001856 res.jsonValue["@odata.type"] =
1857 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1858 res.jsonValue["@odata.context"] =
1859 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1860 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001861
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001862 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 {
1864 return;
1865 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001866
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 // Get single eth interface data, and call the below callback for JSON
1868 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001869 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001870 params[1],
1871 [this, asyncResp, parent_iface_id{std::string(params[0])},
1872 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001873 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001874 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001875 const boost::container::flat_set<IPv4AddressData>
1876 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001877 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1878 const boost::container::flat_set<IPv6AddressData>
1879 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001880 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001881 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001882 parseInterfaceData(asyncResp->res.jsonValue,
1883 parent_iface_id, iface_id, ethData,
Ravi Tejad1d50812019-06-23 16:20:27 -05001884 ipv4Data, ipv4StaticData, ipv6Data,
1885 ipv6StaticData);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001886 }
1887 else
1888 {
1889 // ... otherwise return error
1890 // TODO(Pawel)consider distinguish between non existing
1891 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001892 messages::resourceNotFound(
1893 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001894 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001896 }
1897
Ed Tanous1abe55e2018-09-05 08:30:59 -07001898 void doPatch(crow::Response &res, const crow::Request &req,
1899 const std::vector<std::string> &params) override
1900 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001901 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001902 if (params.size() != 2)
1903 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001904 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001905 return;
1906 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001907
Ed Tanous1abe55e2018-09-05 08:30:59 -07001908 const std::string &parentIfaceId = params[0];
1909 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001910
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001911 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001912 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001913 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1914 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001915 return;
1916 }
1917
Ed Tanous0627a2c2018-11-29 17:09:23 -08001918 bool vlanEnable = false;
1919 uint64_t vlanId = 0;
1920
1921 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1922 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001923 {
1924 return;
1925 }
1926
1927 // Get single eth interface data, and call the below callback for JSON
1928 // preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001929 getEthernetIfaceData(
1930 params[1],
1931 [this, asyncResp, parentIfaceId{std::string(params[0])},
1932 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1933 const bool &success, const EthernetInterfaceData &ethData,
1934 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001935 const boost::container::flat_set<IPv4AddressData>
1936 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001937 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1938 const boost::container::flat_set<IPv6AddressData>
1939 &ipv6StaticData) {
1940 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001941 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001942 auto callback =
1943 [asyncResp](const boost::system::error_code ec) {
1944 if (ec)
1945 {
1946 messages::internalError(asyncResp->res);
1947 }
1948 };
1949
1950 if (vlanEnable == true)
1951 {
1952 crow::connections::systemBus->async_method_call(
1953 std::move(callback), "xyz.openbmc_project.Network",
1954 "/xyz/openbmc_project/network/" + ifaceId,
1955 "org.freedesktop.DBus.Properties", "Set",
1956 "xyz.openbmc_project.Network.VLAN", "Id",
1957 std::variant<uint32_t>(vlanId));
1958 }
1959 else
1960 {
1961 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1962 "vlan interface";
1963 crow::connections::systemBus->async_method_call(
1964 std::move(callback), "xyz.openbmc_project.Network",
1965 std::string("/xyz/openbmc_project/network/") +
1966 ifaceId,
1967 "xyz.openbmc_project.Object.Delete", "Delete");
1968 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001969 }
1970 else
1971 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001972 // TODO(Pawel)consider distinguish between non existing
1973 // object, and other errors
1974 messages::resourceNotFound(
1975 asyncResp->res, "VLAN Network Interface", ifaceId);
1976 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001977 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001978 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001979 }
1980
1981 void doDelete(crow::Response &res, const crow::Request &req,
1982 const std::vector<std::string> &params) override
1983 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001984 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001985 if (params.size() != 2)
1986 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001987 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001988 return;
1989 }
1990
1991 const std::string &parentIfaceId = params[0];
1992 const std::string &ifaceId = params[1];
1993
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001994 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001995 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001996 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1997 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001998 return;
1999 }
2000
2001 // Get single eth interface data, and call the below callback for JSON
2002 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002003 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002004 params[1],
2005 [this, asyncResp, parentIfaceId{std::string(params[0])},
2006 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002007 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002008 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05002009 const boost::container::flat_set<IPv4AddressData>
2010 &ipv4StaticData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002011 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2012 const boost::container::flat_set<IPv6AddressData>
2013 &ipv6StaticData) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002014 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002015 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002016 auto callback =
2017 [asyncResp](const boost::system::error_code ec) {
2018 if (ec)
2019 {
2020 messages::internalError(asyncResp->res);
2021 }
2022 };
2023 crow::connections::systemBus->async_method_call(
2024 std::move(callback), "xyz.openbmc_project.Network",
2025 std::string("/xyz/openbmc_project/network/") + ifaceId,
2026 "xyz.openbmc_project.Object.Delete", "Delete");
2027 }
2028 else
2029 {
2030 // ... otherwise return error
2031 // TODO(Pawel)consider distinguish between non existing
2032 // object, and other errors
2033 messages::resourceNotFound(
2034 asyncResp->res, "VLAN Network Interface", ifaceId);
2035 }
2036 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002037 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002038};
2039
2040/**
2041 * VlanNetworkInterfaceCollection derived class for delivering
2042 * VLANNetworkInterface Collection Schema
2043 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002044class VlanNetworkInterfaceCollection : public Node
2045{
2046 public:
2047 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002048 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002049 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2050 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002051 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002052 entityPrivileges = {
2053 {boost::beast::http::verb::get, {{"Login"}}},
2054 {boost::beast::http::verb::head, {{"Login"}}},
2055 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2056 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2057 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2058 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002059 }
2060
Ed Tanous1abe55e2018-09-05 08:30:59 -07002061 private:
2062 /**
2063 * Functions triggers appropriate requests on DBus
2064 */
2065 void doGet(crow::Response &res, const crow::Request &req,
2066 const std::vector<std::string> &params) override
2067 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002068 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002069 if (params.size() != 1)
2070 {
2071 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002072 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002073 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002074 }
2075
Ed Tanous4a0cb852018-10-15 07:55:04 -07002076 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002077
Ed Tanous4a0cb852018-10-15 07:55:04 -07002078 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002079 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002080 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002081 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002082 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002083 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002084 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002085 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002086 messages::internalError(asyncResp->res);
2087 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002089
2090 if (iface_list.find(rootInterfaceName) == iface_list.end())
2091 {
2092 messages::resourceNotFound(asyncResp->res,
2093 "VLanNetworkInterfaceCollection",
2094 rootInterfaceName);
2095 return;
2096 }
2097
Ed Tanous0f74e642018-11-12 15:17:05 -08002098 asyncResp->res.jsonValue["@odata.type"] =
2099 "#VLanNetworkInterfaceCollection."
2100 "VLanNetworkInterfaceCollection";
2101 asyncResp->res.jsonValue["@odata.context"] =
2102 "/redfish/v1/$metadata"
2103 "#VLanNetworkInterfaceCollection."
2104 "VLanNetworkInterfaceCollection";
2105 asyncResp->res.jsonValue["Name"] =
2106 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002107
Jason M. Billsf12894f2018-10-09 12:45:45 -07002108 nlohmann::json iface_array = nlohmann::json::array();
2109
2110 for (const std::string &iface_item : iface_list)
2111 {
2112 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2113 {
2114 iface_array.push_back(
2115 {{"@odata.id",
2116 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2117 rootInterfaceName + "/VLANs/" + iface_item}});
2118 }
2119 }
2120
Jason M. Billsf12894f2018-10-09 12:45:45 -07002121 asyncResp->res.jsonValue["Members@odata.count"] =
2122 iface_array.size();
2123 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2124 asyncResp->res.jsonValue["@odata.id"] =
2125 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2126 rootInterfaceName + "/VLANs";
2127 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002128 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002129
Ed Tanous1abe55e2018-09-05 08:30:59 -07002130 void doPost(crow::Response &res, const crow::Request &req,
2131 const std::vector<std::string> &params) override
2132 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002133 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002134 if (params.size() != 1)
2135 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002136 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002137 return;
2138 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002139 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002140 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002141 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2142 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002143 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002144 return;
2145 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002146 // Need both vlanId and vlanEnable to service this request
2147 if (!vlanId)
2148 {
2149 messages::propertyMissing(asyncResp->res, "VLANId");
2150 }
2151 if (!vlanEnable)
2152 {
2153 messages::propertyMissing(asyncResp->res, "VLANEnable");
2154 }
2155 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2156 {
2157 return;
2158 }
2159
Ed Tanous4a0cb852018-10-15 07:55:04 -07002160 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002161 auto callback = [asyncResp](const boost::system::error_code ec) {
2162 if (ec)
2163 {
2164 // TODO(ed) make more consistent error messages based on
2165 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002166 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002167 return;
2168 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002169 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002170 };
2171 crow::connections::systemBus->async_method_call(
2172 std::move(callback), "xyz.openbmc_project.Network",
2173 "/xyz/openbmc_project/network",
2174 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002175 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002176 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002177};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002178} // namespace redfish