blob: b06acf013c50b1e57b761eb9282292329c1564ae [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous1abe55e2018-09-05 08:30:59 -070018#include <boost/container/flat_map.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070019#include <boost/container/flat_set.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020020#include <dbus_singleton.hpp>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020021#include <error_messages.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020022#include <node.hpp>
Ed Tanousa24526d2018-12-10 15:17:59 -080023#include <optional>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020024#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080025#include <variant>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010029
30/**
31 * DBus types primitives for several generic DBus interfaces
32 * TODO(Pawel) consider move this to separate file into boost::dbus
33 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using PropertiesMapType = boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080035 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36 int32_t, uint32_t, int64_t, uint64_t, double>>;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010037
Ed Tanous4a0cb852018-10-15 07:55:04 -070038using GetManagedObjects = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039 sdbusplus::message::object_path,
Ed Tanous4a0cb852018-10-15 07:55:04 -070040 std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070041 std::string,
42 boost::container::flat_map<
Ed Tanous029573d2019-02-01 10:57:49 -080043 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
45 int32_t, uint32_t, int64_t, uint64_t, double,
46 std::vector<std::string>>>>>>>;
Ed Tanous4a0cb852018-10-15 07:55:04 -070047
48enum class LinkType
49{
50 Local,
51 Global
52};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010053
54/**
55 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010056 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070057struct IPv4AddressData
58{
59 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070060 std::string address;
61 std::string domain;
62 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 std::string netmask;
64 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070065 LinkType linktype;
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 bool operator<(const IPv4AddressData &obj) const
68 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070069 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
81 uint8_t prefixLength;
82
83 bool operator<(const IPv6AddressData &obj) const
84 {
85 return id < obj.id;
86 }
87};
88/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010089 * Structure for keeping basic single Ethernet Interface information
90 * available from DBus
91 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070092struct EthernetInterfaceData
93{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t speed;
95 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053096 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070097 std::string hostname;
98 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -050099 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700100 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500101 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -0800102 std::vector<std::string> nameservers;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800103 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100104};
105
Ed Tanous4a0cb852018-10-15 07:55:04 -0700106// Helper function that changes bits netmask notation (i.e. /24)
107// into full dot notation
108inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700110 uint32_t value = 0xffffffff << (32 - bits);
111 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
112 std::to_string((value >> 16) & 0xff) + "." +
113 std::to_string((value >> 8) & 0xff) + "." +
114 std::to_string(value & 0xff);
115 return netmask;
116}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100117
Ed Tanous4a0cb852018-10-15 07:55:04 -0700118inline std::string
119 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
120 bool isIPv4)
121{
122 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700124 return "Static";
125 }
126 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
127 {
128 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700130 return "IPv4LinkLocal";
131 }
132 else
133 {
134 return "LinkLocal";
135 }
136 }
137 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
138 {
139 if (isIPv4)
140 {
141 return "DHCP";
142 }
143 else
144 {
145 return "DHCPv6";
146 }
147 }
148 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
149 {
150 return "SLAAC";
151 }
152 return "";
153}
154
Ed Tanous4c9afe42019-05-03 16:59:57 -0700155inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700156 const GetManagedObjects &dbus_data,
157 EthernetInterfaceData &ethData)
158{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700159 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700160 for (const auto &objpath : dbus_data)
161 {
Ed Tanous029573d2019-02-01 10:57:49 -0800162 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700163 {
Ed Tanous029573d2019-02-01 10:57:49 -0800164 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700166 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700167 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700169 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700171 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700173 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800174 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700175 if (mac != nullptr)
176 {
177 ethData.mac_address = *mac;
178 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700180 }
181 }
182 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
183 {
184 for (const auto &propertyPair : ifacePair.second)
185 {
186 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800188 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800189 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700190 if (id != nullptr)
191 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500192 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700193 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700194 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700195 }
196 }
197 else if (ifacePair.first ==
198 "xyz.openbmc_project.Network.EthernetInterface")
199 {
200 for (const auto &propertyPair : ifacePair.second)
201 {
202 if (propertyPair.first == "AutoNeg")
203 {
204 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800205 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700206 if (auto_neg != nullptr)
207 {
208 ethData.auto_neg = *auto_neg;
209 }
210 }
211 else if (propertyPair.first == "Speed")
212 {
213 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800214 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700215 if (speed != nullptr)
216 {
217 ethData.speed = *speed;
218 }
219 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500220 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700221 {
Ed Tanous029573d2019-02-01 10:57:49 -0800222 const std::vector<std::string> *nameservers =
223 sdbusplus::message::variant_ns::get_if<
224 std::vector<std::string>>(
225 &propertyPair.second);
226 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700227 {
Ed Tanous029573d2019-02-01 10:57:49 -0800228 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700229 }
230 }
manojkiraneda2a133282019-02-19 13:09:43 +0530231 else if (propertyPair.first == "DHCPEnabled")
232 {
233 const bool *DHCPEnabled =
234 std::get_if<bool>(&propertyPair.second);
235 if (DHCPEnabled != nullptr)
236 {
237 ethData.DHCPEnabled = *DHCPEnabled;
238 }
239 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800240 else if (propertyPair.first == "DomainName")
241 {
242 const std::vector<std::string> *domainNames =
243 sdbusplus::message::variant_ns::get_if<
244 std::vector<std::string>>(
245 &propertyPair.second);
246 if (domainNames != nullptr)
247 {
248 ethData.domainnames = std::move(*domainNames);
249 }
250 }
Ed Tanous029573d2019-02-01 10:57:49 -0800251 }
252 }
253 }
254 // System configuration shows up in the global namespace, so no need
255 // to check eth number
256 if (ifacePair.first ==
257 "xyz.openbmc_project.Network.SystemConfiguration")
258 {
259 for (const auto &propertyPair : ifacePair.second)
260 {
261 if (propertyPair.first == "HostName")
262 {
263 const std::string *hostname =
264 sdbusplus::message::variant_ns::get_if<std::string>(
265 &propertyPair.second);
266 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700267 {
Ed Tanous029573d2019-02-01 10:57:49 -0800268 ethData.hostname = *hostname;
269 }
270 }
271 else if (propertyPair.first == "DefaultGateway")
272 {
273 const std::string *defaultGateway =
274 sdbusplus::message::variant_ns::get_if<std::string>(
275 &propertyPair.second);
276 if (defaultGateway != nullptr)
277 {
278 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700279 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500281 else if (propertyPair.first == "DefaultGateway6")
282 {
283 const std::string *defaultGateway6 =
284 sdbusplus::message::variant_ns::get_if<std::string>(
285 &propertyPair.second);
286 if (defaultGateway6 != nullptr)
287 {
288 ethData.ipv6_default_gateway = *defaultGateway6;
289 }
290 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 }
292 }
293 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700295 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700296}
297
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500298// Helper function that extracts data for single ethernet ipv6 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700299inline void
300 extractIPV6Data(const std::string &ethiface_id,
301 const GetManagedObjects &dbus_data,
302 boost::container::flat_set<IPv6AddressData> &ipv6_config)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500303{
304 const std::string ipv6PathStart =
305 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
306
307 // Since there might be several IPv6 configurations aligned with
308 // single ethernet interface, loop over all of them
309 for (const auto &objpath : dbus_data)
310 {
311 // Check if proper pattern for object path appears
312 if (boost::starts_with(objpath.first.str, ipv6PathStart))
313 {
314 for (auto &interface : objpath.second)
315 {
316 if (interface.first == "xyz.openbmc_project.Network.IP")
317 {
318 // Instance IPv6AddressData structure, and set as
319 // appropriate
320 std::pair<
321 boost::container::flat_set<IPv6AddressData>::iterator,
322 bool>
Ed Tanous271584a2019-07-09 16:24:22 -0700323 it = ipv6_config.insert(IPv6AddressData{});
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500324 IPv6AddressData &ipv6_address = *it.first;
Ed Tanous271584a2019-07-09 16:24:22 -0700325 ipv6_address.id =
326 objpath.first.str.substr(ipv6PathStart.size());
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500327 for (auto &property : interface.second)
328 {
329 if (property.first == "Address")
330 {
331 const std::string *address =
332 std::get_if<std::string>(&property.second);
333 if (address != nullptr)
334 {
335 ipv6_address.address = *address;
336 }
337 }
338 else if (property.first == "Origin")
339 {
340 const std::string *origin =
341 std::get_if<std::string>(&property.second);
342 if (origin != nullptr)
343 {
344 ipv6_address.origin =
345 translateAddressOriginDbusToRedfish(*origin,
346 false);
347 }
348 }
349 else if (property.first == "PrefixLength")
350 {
351 const uint8_t *prefix =
352 std::get_if<uint8_t>(&property.second);
353 if (prefix != nullptr)
354 {
355 ipv6_address.prefixLength = *prefix;
356 }
357 }
358 else
359 {
360 BMCWEB_LOG_ERROR
361 << "Got extra property: " << property.first
362 << " on the " << objpath.first.str << " object";
363 }
364 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500365 }
366 }
367 }
368 }
369}
370
Ed Tanous4a0cb852018-10-15 07:55:04 -0700371// Helper function that extracts data for single ethernet ipv4 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700372inline void
373 extractIPData(const std::string &ethiface_id,
374 const GetManagedObjects &dbus_data,
375 boost::container::flat_set<IPv4AddressData> &ipv4_config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700376{
377 const std::string ipv4PathStart =
378 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
379
380 // Since there might be several IPv4 configurations aligned with
381 // single ethernet interface, loop over all of them
382 for (const auto &objpath : dbus_data)
383 {
384 // Check if proper pattern for object path appears
385 if (boost::starts_with(objpath.first.str, ipv4PathStart))
386 {
387 for (auto &interface : objpath.second)
388 {
389 if (interface.first == "xyz.openbmc_project.Network.IP")
390 {
391 // Instance IPv4AddressData structure, and set as
392 // appropriate
393 std::pair<
394 boost::container::flat_set<IPv4AddressData>::iterator,
395 bool>
Ed Tanous271584a2019-07-09 16:24:22 -0700396 it = ipv4_config.insert(IPv4AddressData{});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700397 IPv4AddressData &ipv4_address = *it.first;
Ed Tanous271584a2019-07-09 16:24:22 -0700398 ipv4_address.id =
399 objpath.first.str.substr(ipv4PathStart.size());
Ed Tanous4a0cb852018-10-15 07:55:04 -0700400 for (auto &property : interface.second)
401 {
402 if (property.first == "Address")
403 {
404 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800405 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700406 if (address != nullptr)
407 {
408 ipv4_address.address = *address;
409 }
410 }
411 else if (property.first == "Gateway")
412 {
413 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800414 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700415 if (gateway != nullptr)
416 {
417 ipv4_address.gateway = *gateway;
418 }
419 }
420 else if (property.first == "Origin")
421 {
422 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800423 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700424 if (origin != nullptr)
425 {
426 ipv4_address.origin =
427 translateAddressOriginDbusToRedfish(*origin,
428 true);
429 }
430 }
431 else if (property.first == "PrefixLength")
432 {
433 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800434 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700435 if (mask != nullptr)
436 {
437 // convert it to the string
438 ipv4_address.netmask = getNetmask(*mask);
439 }
440 }
441 else
442 {
443 BMCWEB_LOG_ERROR
444 << "Got extra property: " << property.first
445 << " on the " << objpath.first.str << " object";
446 }
447 }
448 // Check if given address is local, or global
449 ipv4_address.linktype =
450 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700451 ? LinkType::Local
452 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700453 }
454 }
455 }
456 }
457}
458
459/**
460 * @brief Sets given Id on the given VLAN interface through D-Bus
461 *
462 * @param[in] ifaceId Id of VLAN interface that should be modified
463 * @param[in] inputVlanId New ID of the VLAN
464 * @param[in] callback Function that will be called after the operation
465 *
466 * @return None.
467 */
468template <typename CallbackFunc>
469void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
470 CallbackFunc &&callback)
471{
472 crow::connections::systemBus->async_method_call(
473 callback, "xyz.openbmc_project.Network",
474 std::string("/xyz/openbmc_project/network/") + ifaceId,
475 "org.freedesktop.DBus.Properties", "Set",
476 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800477 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700478}
479
480/**
481 * @brief Helper function that verifies IP address to check if it is in
482 * proper format. If bits pointer is provided, also calculates active
483 * bit count for Subnet Mask.
484 *
485 * @param[in] ip IP that will be verified
486 * @param[out] bits Calculated mask in bits notation
487 *
488 * @return true in case of success, false otherwise
489 */
490inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
491 uint8_t *bits = nullptr)
492{
493 std::vector<std::string> bytesInMask;
494
495 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496
497 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700498 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700500 return false;
501 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502
Ed Tanous4a0cb852018-10-15 07:55:04 -0700503 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700505 *bits = 0;
506 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507
Ed Tanous4a0cb852018-10-15 07:55:04 -0700508 char *endPtr;
509 long previousValue = 255;
510 bool firstZeroInByteHit;
511 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700513 if (byte.empty())
514 {
515 return false;
516 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517
Ed Tanous4a0cb852018-10-15 07:55:04 -0700518 // Use strtol instead of stroi to avoid exceptions
519 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520
Ed Tanous4a0cb852018-10-15 07:55:04 -0700521 // endPtr should point to the end of the string, otherwise given string
522 // is not 100% number
523 if (*endPtr != '\0')
524 {
525 return false;
526 }
527
528 // Value should be contained in byte
529 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
531 return false;
532 }
533
534 if (bits != nullptr)
535 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700536 // Mask has to be continuous between bytes
537 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 {
539 return false;
540 }
541
Ed Tanous4a0cb852018-10-15 07:55:04 -0700542 // Mask has to be continuous inside bytes
543 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544
Ed Tanous4a0cb852018-10-15 07:55:04 -0700545 // Count bits
546 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700550 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700552 // Continuity not preserved
553 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700554 }
555 else
556 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700557 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 }
559 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 else
561 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700562 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700564 }
565 }
566
567 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 }
569
Ed Tanous4a0cb852018-10-15 07:55:04 -0700570 return true;
571}
572
573/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700574 * @brief Deletes given IPv4 interface
Ed Tanous4a0cb852018-10-15 07:55:04 -0700575 *
576 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700577 * @param[in] ipHash DBus Hash id of IP that should be deleted
578 * @param[io] asyncResp Response object that will be returned to client
579 *
580 * @return None
581 */
582inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700583 const std::shared_ptr<AsyncResp> asyncResp)
584{
585 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700586 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 if (ec)
588 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800589 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100590 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700591 },
592 "xyz.openbmc_project.Network",
593 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
594 "xyz.openbmc_project.Object.Delete", "Delete");
595}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596
Ed Tanous4a0cb852018-10-15 07:55:04 -0700597/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700598 * @brief Creates a static IPv4 entry
Ed Tanous4a0cb852018-10-15 07:55:04 -0700599 *
Johnathan Mantey01784822019-06-18 12:44:21 -0700600 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
601 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
602 * @param[in] gateway IPv4 address of this interfaces gateway
603 * @param[in] address IPv4 address to assign to this interface
604 * @param[io] asyncResp Response object that will be returned to client
Ed Tanous4a0cb852018-10-15 07:55:04 -0700605 *
606 * @return None
607 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000608inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
Johnathan Mantey01784822019-06-18 12:44:21 -0700609 uint8_t prefixLength, const std::string &gateway,
Ed Tanousb01bf292019-03-25 19:25:26 +0000610 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700611 std::shared_ptr<AsyncResp> asyncResp)
612{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700613 crow::connections::systemBus->async_method_call(
Johnathan Mantey01784822019-06-18 12:44:21 -0700614 [asyncResp](const boost::system::error_code ec) {
615 if (ec)
616 {
617 messages::internalError(asyncResp->res);
618 }
619 },
620 "xyz.openbmc_project.Network",
Ed Tanous4a0cb852018-10-15 07:55:04 -0700621 "/xyz/openbmc_project/network/" + ifaceId,
622 "xyz.openbmc_project.Network.IP.Create", "IP",
Johnathan Mantey01784822019-06-18 12:44:21 -0700623 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, prefixLength,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700624 gateway);
625}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500626
627/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700628 * @brief Deletes the IPv4 entry for this interface and creates a replacement
629 * static IPv4 entry
630 *
631 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
632 * @param[in] id The unique hash entry identifying the DBus entry
633 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
634 * @param[in] gateway IPv4 address of this interfaces gateway
635 * @param[in] address IPv4 address to assign to this interface
636 * @param[io] asyncResp Response object that will be returned to client
637 *
638 * @return None
639 */
640inline void deleteAndCreateIPv4(const std::string &ifaceId,
641 const std::string &id, uint8_t prefixLength,
642 const std::string &gateway,
643 const std::string &address,
644 std::shared_ptr<AsyncResp> asyncResp)
645{
646 crow::connections::systemBus->async_method_call(
647 [asyncResp, ifaceId, address, prefixLength,
648 gateway](const boost::system::error_code ec) {
649 if (ec)
650 {
651 messages::internalError(asyncResp->res);
652 }
653 crow::connections::systemBus->async_method_call(
654 [asyncResp](const boost::system::error_code ec) {
655 if (ec)
656 {
657 messages::internalError(asyncResp->res);
658 }
659 },
660 "xyz.openbmc_project.Network",
661 "/xyz/openbmc_project/network/" + ifaceId,
662 "xyz.openbmc_project.Network.IP.Create", "IP",
663 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address,
664 prefixLength, gateway);
665 },
666 "xyz.openbmc_project.Network",
667 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + id,
668 "xyz.openbmc_project.Object.Delete", "Delete");
669}
670
671/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500672 * @brief Deletes given IPv6
673 *
674 * @param[in] ifaceId Id of interface whose IP should be deleted
675 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500676 * @param[io] asyncResp Response object that will be returned to client
677 *
678 * @return None
679 */
680inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500681 const std::shared_ptr<AsyncResp> asyncResp)
682{
683 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700684 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500685 if (ec)
686 {
687 messages::internalError(asyncResp->res);
688 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500689 },
690 "xyz.openbmc_project.Network",
691 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
692 "xyz.openbmc_project.Object.Delete", "Delete");
693}
694
695/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700696 * @brief Deletes the IPv6 entry for this interface and creates a replacement
697 * static IPv6 entry
698 *
699 * @param[in] ifaceId Id of interface upon which to create the IPv6 entry
700 * @param[in] id The unique hash entry identifying the DBus entry
701 * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
702 * @param[in] address IPv6 address to assign to this interface
703 * @param[io] asyncResp Response object that will be returned to client
704 *
705 * @return None
706 */
707inline void deleteAndCreateIPv6(const std::string &ifaceId,
708 const std::string &id, uint8_t prefixLength,
709 const std::string &address,
710 std::shared_ptr<AsyncResp> asyncResp)
711{
712 crow::connections::systemBus->async_method_call(
713 [asyncResp, ifaceId, address,
714 prefixLength](const boost::system::error_code ec) {
715 if (ec)
716 {
717 messages::internalError(asyncResp->res);
718 }
719 crow::connections::systemBus->async_method_call(
720 [asyncResp](const boost::system::error_code ec) {
721 if (ec)
722 {
723 messages::internalError(asyncResp->res);
724 }
725 },
726 "xyz.openbmc_project.Network",
727 "/xyz/openbmc_project/network/" + ifaceId,
728 "xyz.openbmc_project.Network.IP.Create", "IP",
729 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address,
730 prefixLength, "");
731 },
732 "xyz.openbmc_project.Network",
733 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + id,
734 "xyz.openbmc_project.Object.Delete", "Delete");
735}
736
737/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500738 * @brief Creates IPv6 with given data
739 *
740 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500741 * @param[in] prefixLength Prefix length that needs to be added
742 * @param[in] address IP address that needs to be added
743 * @param[io] asyncResp Response object that will be returned to client
744 *
745 * @return None
746 */
Johnathan Mantey01784822019-06-18 12:44:21 -0700747inline void createIPv6(const std::string &ifaceId, uint8_t prefixLength,
748 const std::string &address,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500749 std::shared_ptr<AsyncResp> asyncResp)
750{
751 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
752 if (ec)
753 {
754 messages::internalError(asyncResp->res);
755 }
756 };
757 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
758 // does not have assosiated gateway property
759 crow::connections::systemBus->async_method_call(
760 std::move(createIpHandler), "xyz.openbmc_project.Network",
761 "/xyz/openbmc_project/network/" + ifaceId,
762 "xyz.openbmc_project.Network.IP.Create", "IP",
763 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
764 "");
765}
766
manojkiraneda2a133282019-02-19 13:09:43 +0530767using GetAllPropertiesType =
768 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
769
770inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
771{
772 auto getConfig = [asyncResp](const boost::system::error_code error_code,
773 const GetAllPropertiesType &dbus_data) {
774 if (error_code)
775 {
776 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
777 messages::internalError(asyncResp->res);
778 return;
779 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500780 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530781 for (const auto &property : dbus_data)
782 {
783 auto value =
784 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
785
786 if (value == nullptr)
787 {
788 continue;
789 }
790 if (property.first == "DNSEnabled")
791 {
792 DHCPConfigTypeJson["UseDNSServers"] = *value;
793 }
794 else if (property.first == "HostNameEnabled")
795 {
796 DHCPConfigTypeJson["UseDomainName"] = *value;
797 }
798 else if (property.first == "NTPEnabled")
799 {
800 DHCPConfigTypeJson["UseNTPServers"] = *value;
801 }
802 }
803 };
804 crow::connections::systemBus->async_method_call(
805 std::move(getConfig), "xyz.openbmc_project.Network",
806 "/xyz/openbmc_project/network/config/dhcp",
807 "org.freedesktop.DBus.Properties", "GetAll",
808 "xyz.openbmc_project.Network.DHCPConfiguration");
809}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810
Ed Tanous4a0cb852018-10-15 07:55:04 -0700811/**
812 * Function that retrieves all properties for given Ethernet Interface
813 * Object
814 * from EntityManager Network Manager
815 * @param ethiface_id a eth interface id to query on DBus
816 * @param callback a function that shall be called to convert Dbus output
817 * into JSON
818 */
819template <typename CallbackFunc>
820void getEthernetIfaceData(const std::string &ethiface_id,
821 CallbackFunc &&callback)
822{
823 crow::connections::systemBus->async_method_call(
824 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
825 const boost::system::error_code error_code,
826 const GetManagedObjects &resp) {
827 EthernetInterfaceData ethData{};
828 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500829 boost::container::flat_set<IPv6AddressData> ipv6Data;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700830
831 if (error_code)
832 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700833 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700834 return;
835 }
836
Ed Tanous4c9afe42019-05-03 16:59:57 -0700837 bool found =
838 extractEthernetInterfaceData(ethiface_id, resp, ethData);
839 if (!found)
840 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700841 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700842 return;
843 }
844
Johnathan Mantey01784822019-06-18 12:44:21 -0700845 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700846 // Fix global GW
847 for (IPv4AddressData &ipv4 : ipv4Data)
848 {
Ravi Tejac6191412019-07-30 00:53:50 -0500849 if (((ipv4.linktype == LinkType::Global) &&
850 (ipv4.gateway == "0.0.0.0")) ||
851 (ipv4.origin == "DHCP"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700853 ipv4.gateway = ethData.default_gateway;
854 }
855 }
856
Johnathan Mantey01784822019-06-18 12:44:21 -0700857 extractIPV6Data(ethiface_id, resp, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700858 // Finally make a callback with usefull data
Johnathan Mantey01784822019-06-18 12:44:21 -0700859 callback(true, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700860 },
861 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
862 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous271584a2019-07-09 16:24:22 -0700863}
Ed Tanous4a0cb852018-10-15 07:55:04 -0700864
865/**
866 * Function that retrieves all Ethernet Interfaces available through Network
867 * Manager
868 * @param callback a function that shall be called to convert Dbus output
869 * into JSON.
870 */
871template <typename CallbackFunc>
872void getEthernetIfaceList(CallbackFunc &&callback)
873{
874 crow::connections::systemBus->async_method_call(
875 [callback{std::move(callback)}](
876 const boost::system::error_code error_code,
877 GetManagedObjects &resp) {
878 // Callback requires vector<string> to retrieve all available
879 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700880 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700881 iface_list.reserve(resp.size());
882 if (error_code)
883 {
884 callback(false, iface_list);
885 return;
886 }
887
888 // Iterate over all retrieved ObjectPaths.
889 for (const auto &objpath : resp)
890 {
891 // And all interfaces available for certain ObjectPath.
892 for (const auto &interface : objpath.second)
893 {
894 // If interface is
895 // xyz.openbmc_project.Network.EthernetInterface, this is
896 // what we're looking for.
897 if (interface.first ==
898 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700900 // Cut out everyting until last "/", ...
901 const std::string &iface_id = objpath.first.str;
902 std::size_t last_pos = iface_id.rfind("/");
903 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700905 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700906 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 }
908 }
909 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700910 }
911 // Finally make a callback with useful data
912 callback(true, iface_list);
913 },
914 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
915 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous271584a2019-07-09 16:24:22 -0700916}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100917
918/**
919 * EthernetCollection derived class for delivering Ethernet Collection Schema
920 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921class EthernetCollection : public Node
922{
923 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700924 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700925 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700926 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700928 entityPrivileges = {
929 {boost::beast::http::verb::get, {{"Login"}}},
930 {boost::beast::http::verb::head, {{"Login"}}},
931 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
932 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
933 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
934 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
935 }
936
937 private:
938 /**
939 * Functions triggers appropriate requests on DBus
940 */
941 void doGet(crow::Response &res, const crow::Request &req,
942 const std::vector<std::string> &params) override
943 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800944 res.jsonValue["@odata.type"] =
945 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
946 res.jsonValue["@odata.context"] =
947 "/redfish/v1/"
948 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
949 res.jsonValue["@odata.id"] =
950 "/redfish/v1/Managers/bmc/EthernetInterfaces";
951 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
952 res.jsonValue["Description"] =
953 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -0700954 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700955 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700957 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -0700958 [asyncResp](
959 const bool &success,
960 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700961 if (!success)
962 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700963 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -0700964 return;
965 }
966
Ed Tanous4c9afe42019-05-03 16:59:57 -0700967 nlohmann::json &iface_array =
968 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -0700969 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500970 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700971 for (const std::string &iface_item : iface_list)
972 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500973 std::size_t found = iface_item.find(tag);
974 if (found == std::string::npos)
975 {
976 iface_array.push_back(
977 {{"@odata.id",
978 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
979 iface_item}});
980 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700981 }
982
Ed Tanous4c9afe42019-05-03 16:59:57 -0700983 asyncResp->res.jsonValue["Members@odata.count"] =
984 iface_array.size();
985 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -0700986 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700987 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700988 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100989};
990
991/**
992 * EthernetInterface derived class for delivering Ethernet Schema
993 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994class EthernetInterface : public Node
995{
996 public:
997 /*
998 * Default Constructor
999 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001000 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001001 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001002 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001003 std::string())
1004 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001005 entityPrivileges = {
1006 {boost::beast::http::verb::get, {{"Login"}}},
1007 {boost::beast::http::verb::head, {{"Login"}}},
1008 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1009 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1010 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1011 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001012 }
1013
Ed Tanous1abe55e2018-09-05 08:30:59 -07001014 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001015 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001016 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001017 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001018 asyncResp->res.jsonValue["HostName"] = hostname;
1019 crow::connections::systemBus->async_method_call(
1020 [asyncResp](const boost::system::error_code ec) {
1021 if (ec)
1022 {
1023 messages::internalError(asyncResp->res);
1024 }
1025 },
1026 "xyz.openbmc_project.Network",
1027 "/xyz/openbmc_project/network/config",
1028 "org.freedesktop.DBus.Properties", "Set",
1029 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001030 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001031 }
1032
Ratan Guptad5776652019-03-03 08:47:22 +05301033 void handleMACAddressPatch(const std::string &ifaceId,
1034 const std::string &macAddress,
1035 const std::shared_ptr<AsyncResp> &asyncResp)
1036 {
1037 crow::connections::systemBus->async_method_call(
1038 [asyncResp, macAddress](const boost::system::error_code ec) {
1039 if (ec)
1040 {
1041 messages::internalError(asyncResp->res);
1042 return;
1043 }
Ratan Guptad5776652019-03-03 08:47:22 +05301044 },
1045 "xyz.openbmc_project.Network",
1046 "/xyz/openbmc_project/network/" + ifaceId,
1047 "org.freedesktop.DBus.Properties", "Set",
1048 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1049 std::variant<std::string>(macAddress));
1050 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001051
Jennifer Leeda131a92019-04-24 15:13:55 -07001052 void setDHCPEnabled(const std::string &ifaceId,
1053 const std::string &propertyName, const bool &value,
1054 const std::shared_ptr<AsyncResp> asyncResp)
1055 {
1056 crow::connections::systemBus->async_method_call(
1057 [asyncResp](const boost::system::error_code ec) {
1058 if (ec)
1059 {
1060 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1061 messages::internalError(asyncResp->res);
1062 return;
1063 }
1064 },
1065 "xyz.openbmc_project.Network",
1066 "/xyz/openbmc_project/network/" + ifaceId,
1067 "org.freedesktop.DBus.Properties", "Set",
1068 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1069 std::variant<bool>{value});
1070 }
1071 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1072 const std::shared_ptr<AsyncResp> asyncResp)
1073 {
1074 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1075 crow::connections::systemBus->async_method_call(
1076 [asyncResp](const boost::system::error_code ec) {
1077 if (ec)
1078 {
1079 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1080 messages::internalError(asyncResp->res);
1081 return;
1082 }
1083 },
1084 "xyz.openbmc_project.Network",
1085 "/xyz/openbmc_project/network/config/dhcp",
1086 "org.freedesktop.DBus.Properties", "Set",
1087 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1088 std::variant<bool>{value});
1089 }
Ratan Guptad5776652019-03-03 08:47:22 +05301090
Jennifer Leeda131a92019-04-24 15:13:55 -07001091 void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1092 const std::shared_ptr<AsyncResp> asyncResp)
1093 {
1094 std::optional<bool> dhcpEnabled;
1095 std::optional<bool> useDNSServers;
1096 std::optional<bool> useDomainName;
1097 std::optional<bool> useNTPServers;
1098
1099 if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1100 dhcpEnabled, "UseDNSServers", useDNSServers,
1101 "UseDomainName", useDomainName,
1102 "UseNTPServers", useNTPServers))
1103 {
1104 return;
1105 }
1106
1107 if (dhcpEnabled)
1108 {
1109 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1110 setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1111 }
1112
1113 if (useDNSServers)
1114 {
1115 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1116 setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1117 }
1118
1119 if (useDomainName)
1120 {
1121 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1122 setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1123 }
1124
1125 if (useNTPServers)
1126 {
1127 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1128 setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1129 }
1130 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001131
1132 boost::container::flat_set<IPv4AddressData>::const_iterator
1133 GetNextStaticIPEntry(
1134 boost::container::flat_set<IPv4AddressData>::const_iterator head,
1135 boost::container::flat_set<IPv4AddressData>::const_iterator end)
1136 {
1137 for (; head != end; head++)
1138 {
1139 if (head->origin == "Static")
1140 {
1141 return head;
1142 }
1143 }
1144 return end;
1145 }
1146
1147 boost::container::flat_set<IPv6AddressData>::const_iterator
1148 GetNextStaticIPEntry(
1149 boost::container::flat_set<IPv6AddressData>::const_iterator head,
1150 boost::container::flat_set<IPv6AddressData>::const_iterator end)
1151 {
1152 for (; head != end; head++)
1153 {
1154 if (head->origin == "Static")
1155 {
1156 return head;
1157 }
1158 }
1159 return end;
1160 }
1161
Ravi Tejad1d50812019-06-23 16:20:27 -05001162 void handleIPv4StaticPatch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301163 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001164 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001165 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001166 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001167 if ((!input.is_array()) || input.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301168 {
1169 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Ravi Tejad1d50812019-06-23 16:20:27 -05001170 "IPv4StaticAddresses");
Ratan Guptaf476acb2019-03-02 16:46:57 +05301171 return;
1172 }
1173
Ed Tanous271584a2019-07-09 16:24:22 -07001174 unsigned entryIdx = 1;
Johnathan Mantey01784822019-06-18 12:44:21 -07001175 // Find the first static IP address currently active on the NIC and
1176 // match it to the first JSON element in the IPv4StaticAddresses array.
1177 // Match each subsequent JSON element to the next static IP programmed
1178 // into the NIC.
1179 boost::container::flat_set<IPv4AddressData>::const_iterator NICIPentry =
1180 GetNextStaticIPEntry(ipv4Data.cbegin(), ipv4Data.cend());
1181
Ed Tanous537174c2018-12-10 15:09:31 -08001182 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001183 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001184 std::string pathString =
Ravi Tejad1d50812019-06-23 16:20:27 -05001185 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001186
Johnathan Mantey01784822019-06-18 12:44:21 -07001187 if (!thisJson.is_null() && !thisJson.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301188 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001189 std::optional<std::string> address;
1190 std::optional<std::string> subnetMask;
1191 std::optional<std::string> gateway;
1192
1193 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1194 address, "SubnetMask", subnetMask,
1195 "Gateway", gateway))
Ratan Guptaf476acb2019-03-02 16:46:57 +05301196 {
1197 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001198 asyncResp->res, thisJson.dump(), pathString);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301199 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301200 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301201
Johnathan Mantey01784822019-06-18 12:44:21 -07001202 // Find the address/subnet/gateway values. Any values that are
1203 // not explicitly provided are assumed to be unmodified from the
1204 // current state of the interface. Merge existing state into the
1205 // current request.
Ed Tanous271584a2019-07-09 16:24:22 -07001206 const std::string *addr = nullptr;
1207 const std::string *gw = nullptr;
Johnathan Mantey01784822019-06-18 12:44:21 -07001208 uint8_t prefixLength = 0;
1209 bool errorInEntry = false;
1210 if (address)
Ratan Gupta9474b372019-03-01 15:13:37 +05301211 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001212 if (ipv4VerifyIpAndGetBitcount(*address))
1213 {
1214 addr = &(*address);
1215 }
1216 else
1217 {
1218 messages::propertyValueFormatError(
1219 asyncResp->res, *address, pathString + "/Address");
1220 errorInEntry = true;
1221 }
1222 }
1223 else if (NICIPentry != ipv4Data.cend())
1224 {
1225 addr = &(NICIPentry->address);
Ratan Gupta9474b372019-03-01 15:13:37 +05301226 }
1227 else
1228 {
1229 messages::propertyMissing(asyncResp->res,
1230 pathString + "/Address");
Johnathan Mantey01784822019-06-18 12:44:21 -07001231 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001232 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301233
1234 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001236 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
1237 {
1238 messages::propertyValueFormatError(
1239 asyncResp->res, *subnetMask,
1240 pathString + "/SubnetMask");
1241 errorInEntry = true;
1242 }
1243 }
1244 else if (NICIPentry != ipv4Data.cend())
1245 {
1246 if (!ipv4VerifyIpAndGetBitcount(NICIPentry->netmask,
1247 &prefixLength))
1248 {
1249 messages::propertyValueFormatError(
1250 asyncResp->res, NICIPentry->netmask,
1251 pathString + "/SubnetMask");
1252 errorInEntry = true;
1253 }
1254 }
1255 else
1256 {
1257 messages::propertyMissing(asyncResp->res,
1258 pathString + "/SubnetMask");
1259 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001260 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301261
Ratan Guptaf476acb2019-03-02 16:46:57 +05301262 if (gateway)
1263 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001264 if (ipv4VerifyIpAndGetBitcount(*gateway))
1265 {
1266 gw = &(*gateway);
1267 }
1268 else
1269 {
1270 messages::propertyValueFormatError(
1271 asyncResp->res, *gateway, pathString + "/Gateway");
1272 errorInEntry = true;
1273 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301274 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001275 else if (NICIPentry != ipv4Data.cend())
1276 {
1277 gw = &NICIPentry->gateway;
1278 }
1279 else
Ed Tanous4a0cb852018-10-15 07:55:04 -07001280 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001281 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001282 pathString + "/Gateway");
Johnathan Mantey01784822019-06-18 12:44:21 -07001283 errorInEntry = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001284 }
1285
Johnathan Mantey01784822019-06-18 12:44:21 -07001286 if (errorInEntry)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001287 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001288 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001289 }
1290
Johnathan Mantey01784822019-06-18 12:44:21 -07001291 if (NICIPentry != ipv4Data.cend())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001292 {
Ed Tanous271584a2019-07-09 16:24:22 -07001293 if (gw != nullptr || addr != nullptr)
1294 {
1295 // Shouldn't be possible based on errorInEntry, but
1296 // it flags -wmaybe-uninitialized in the compiler,
1297 // so defend against that
1298 return;
1299 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001300 deleteAndCreateIPv4(ifaceId, NICIPentry->id, prefixLength,
1301 *gw, *addr, asyncResp);
1302 NICIPentry =
1303 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
Ed Tanous4a0cb852018-10-15 07:55:04 -07001304 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001305 else
1306 {
1307 createIPv4(ifaceId, entryIdx, prefixLength, *gateway,
1308 *address, asyncResp);
1309 }
1310 entryIdx++;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001311 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001312 else
1313 {
1314 if (NICIPentry == ipv4Data.cend())
1315 {
1316 // Requesting a DELETE/DO NOT MODIFY action for an item
1317 // that isn't present on the eth(n) interface. Input JSON is
1318 // in error, so bail out.
1319 if (thisJson.is_null())
1320 {
1321 messages::resourceCannotBeDeleted(asyncResp->res);
1322 return;
1323 }
1324 else
1325 {
1326 messages::propertyValueFormatError(
1327 asyncResp->res, thisJson.dump(), pathString);
1328 return;
1329 }
1330 }
1331
1332 if (thisJson.is_null())
1333 {
1334 deleteIPv4(ifaceId, NICIPentry->id, asyncResp);
1335 }
1336 if (NICIPentry != ipv4Data.cend())
1337 {
1338 NICIPentry =
1339 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
1340 }
1341 entryIdx++;
1342 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001343 }
1344 }
1345
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001346 void handleStaticNameServersPatch(
1347 const std::string &ifaceId,
1348 const std::vector<std::string> &updatedStaticNameServers,
1349 const std::shared_ptr<AsyncResp> &asyncResp)
1350 {
1351 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001352 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001353 if (ec)
1354 {
1355 messages::internalError(asyncResp->res);
1356 return;
1357 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001358 },
1359 "xyz.openbmc_project.Network",
1360 "/xyz/openbmc_project/network/" + ifaceId,
1361 "org.freedesktop.DBus.Properties", "Set",
1362 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1363 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1364 }
1365
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001366 void handleIPv6StaticAddressesPatch(
1367 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001368 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001369 const std::shared_ptr<AsyncResp> asyncResp)
1370 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001371 if (!input.is_array() || input.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001372 {
1373 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1374 "IPv6StaticAddresses");
1375 return;
1376 }
Ed Tanous271584a2019-07-09 16:24:22 -07001377 size_t entryIdx = 1;
Johnathan Mantey01784822019-06-18 12:44:21 -07001378 boost::container::flat_set<IPv6AddressData>::const_iterator NICIPentry =
1379 GetNextStaticIPEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001380 for (nlohmann::json &thisJson : input)
1381 {
1382 std::string pathString =
1383 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1384
Johnathan Mantey01784822019-06-18 12:44:21 -07001385 if (!thisJson.is_null() && !thisJson.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001386 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001387 std::optional<std::string> address;
1388 std::optional<uint8_t> prefixLength;
1389
1390 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1391 address, "PrefixLength", prefixLength))
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001392 {
1393 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001394 asyncResp->res, thisJson.dump(), pathString);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001395 return;
1396 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001397
Johnathan Mantey01784822019-06-18 12:44:21 -07001398 const std::string *addr;
1399 uint8_t prefix;
1400
1401 // Find the address and prefixLength values. Any values that are
1402 // not explicitly provided are assumed to be unmodified from the
1403 // current state of the interface. Merge existing state into the
1404 // current request.
1405 if (address)
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001406 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001407 addr = &(*address);
1408 }
1409 else if (NICIPentry != ipv6Data.end())
1410 {
1411 addr = &(NICIPentry->address);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001412 }
1413 else
1414 {
1415 messages::propertyMissing(asyncResp->res,
1416 pathString + "/Address");
1417 return;
1418 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001419
1420 if (prefixLength)
1421 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001422 prefix = *prefixLength;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001423 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001424 else if (NICIPentry != ipv6Data.end())
1425 {
1426 prefix = NICIPentry->prefixLength;
1427 }
1428 else
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001429 {
1430 messages::propertyMissing(asyncResp->res,
1431 pathString + "/PrefixLength");
Johnathan Mantey01784822019-06-18 12:44:21 -07001432 return;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001433 }
1434
Johnathan Mantey01784822019-06-18 12:44:21 -07001435 if (NICIPentry != ipv6Data.end())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001436 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001437 deleteAndCreateIPv6(ifaceId, NICIPentry->id, prefix, *addr,
1438 asyncResp);
1439 NICIPentry =
1440 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1441 }
1442 else
1443 {
1444 createIPv6(ifaceId, *prefixLength, *addr, asyncResp);
1445 }
1446 entryIdx++;
1447 }
1448 else
1449 {
1450 if (NICIPentry == ipv6Data.end())
1451 {
1452 // Requesting a DELETE/DO NOT MODIFY action for an item
1453 // that isn't present on the eth(n) interface. Input JSON is
1454 // in error, so bail out.
1455 if (thisJson.is_null())
1456 {
1457 messages::resourceCannotBeDeleted(asyncResp->res);
1458 return;
1459 }
1460 else
1461 {
1462 messages::propertyValueFormatError(
1463 asyncResp->res, thisJson.dump(), pathString);
1464 return;
1465 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001466 }
1467
Johnathan Mantey01784822019-06-18 12:44:21 -07001468 if (thisJson.is_null())
1469 {
1470 deleteIPv6(ifaceId, NICIPentry->id, asyncResp);
1471 }
1472 if (NICIPentry != ipv6Data.cend())
1473 {
1474 NICIPentry =
1475 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1476 }
1477 entryIdx++;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001478 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001479 }
1480 }
1481
Ed Tanous0f74e642018-11-12 15:17:05 -08001482 void parseInterfaceData(
1483 nlohmann::json &json_response, const std::string &iface_id,
1484 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001485 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001486 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001487 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001488 json_response["Id"] = iface_id;
1489 json_response["@odata.id"] =
1490 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001491 json_response["InterfaceEnabled"] = true;
1492 if (ethData.speed == 0)
1493 {
1494 json_response["LinkStatus"] = "NoLink";
1495 json_response["Status"] = {
1496 {"Health", "OK"},
1497 {"State", "Disabled"},
1498 };
1499 }
1500 else
1501 {
1502 json_response["LinkStatus"] = "LinkUp";
1503 json_response["Status"] = {
1504 {"Health", "OK"},
1505 {"State", "Enabled"},
1506 };
1507 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001508 json_response["SpeedMbps"] = ethData.speed;
1509 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001510 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301511
Ed Tanous4a0cb852018-10-15 07:55:04 -07001512 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001513 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001514 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001515 if (!ethData.domainnames.empty())
1516 {
1517 json_response["FQDN"] =
1518 ethData.hostname + "." + ethData.domainnames[0];
1519 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001520 }
1521
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001522 json_response["VLANs"] = {
1523 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1524 iface_id + "/VLANs"}};
1525
Ed Tanous029573d2019-02-01 10:57:49 -08001526 json_response["NameServers"] = ethData.nameservers;
Manojkiran Eda95f86462019-08-07 15:07:54 +05301527
1528 if (!ethData.DHCPEnabled)
1529 {
1530 json_response["StaticNameServers"] = ethData.nameservers;
1531 }
1532 else
1533 {
Manojkiran Edaf1a3cae2019-08-27 14:23:10 +05301534 json_response["StaticNameServers"] = nlohmann::json::array();
Manojkiran Eda95f86462019-08-07 15:07:54 +05301535 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536
Ravi Tejad1d50812019-06-23 16:20:27 -05001537 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001538 nlohmann::json &ipv4_static_array =
1539 json_response["IPv4StaticAddresses"];
Ravi Tejad1d50812019-06-23 16:20:27 -05001540 ipv4_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001541 ipv4_static_array = nlohmann::json::array();
Ravi Tejad1d50812019-06-23 16:20:27 -05001542 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001544
1545 std::string gatewayStr = ipv4_config.gateway;
1546 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001548 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001550
1551 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1552 {"SubnetMask", ipv4_config.netmask},
1553 {"Address", ipv4_config.address},
1554 {"Gateway", gatewayStr}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001555 if (ipv4_config.origin == "Static")
Ravi Tejad1d50812019-06-23 16:20:27 -05001556 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001557 ipv4_static_array.push_back(
1558 {{"AddressOrigin", ipv4_config.origin},
1559 {"SubnetMask", ipv4_config.netmask},
1560 {"Address", ipv4_config.address},
1561 {"Gateway", gatewayStr}});
Ravi Tejad1d50812019-06-23 16:20:27 -05001562 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001563 }
1564
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001565 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001566
1567 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001568 nlohmann::json &ipv6_static_array =
1569 json_response["IPv6StaticAddresses"];
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001570 ipv6_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001571 ipv6_static_array = nlohmann::json::array();
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001572 for (auto &ipv6_config : ipv6Data)
1573 {
1574 ipv6_array.push_back({{"Address", ipv6_config.address},
1575 {"PrefixLength", ipv6_config.prefixLength},
1576 {"AddressOrigin", ipv6_config.origin}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001577 if (ipv6_config.origin == "Static")
1578 {
1579 ipv6_static_array.push_back(
1580 {{"Address", ipv6_config.address},
1581 {"PrefixLength", ipv6_config.prefixLength},
1582 {"AddressOrigin", ipv6_config.origin}});
1583 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001584 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585 }
1586
1587 /**
1588 * Functions triggers appropriate requests on DBus
1589 */
1590 void doGet(crow::Response &res, const crow::Request &req,
1591 const std::vector<std::string> &params) override
1592 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001593 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001594 if (params.size() != 1)
1595 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001596 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001597 return;
1598 }
1599
Ed Tanous4a0cb852018-10-15 07:55:04 -07001600 getEthernetIfaceData(
1601 params[0],
1602 [this, asyncResp, iface_id{std::string(params[0])}](
1603 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001604 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001605 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001606 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001607 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001608 // TODO(Pawel)consider distinguish between non existing
1609 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001610 messages::resourceNotFound(asyncResp->res,
1611 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001612 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001613 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001614
1615 // because this has no dependence on the interface at this
1616 // point, it needs to be done after we know the interface
1617 // exists, not before.
1618 getDHCPConfigData(asyncResp);
1619
Ed Tanous0f74e642018-11-12 15:17:05 -08001620 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001621 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001622 asyncResp->res.jsonValue["@odata.context"] =
Johnathan Mantey01784822019-06-18 12:44:21 -07001623 "/redfish/v1/"
1624 "$metadata#EthernetInterface.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001625 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1626 asyncResp->res.jsonValue["Description"] =
1627 "Management Network Interface";
1628
1629 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
Johnathan Mantey01784822019-06-18 12:44:21 -07001630 ipv4Data, ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001631 });
1632 }
1633
1634 void doPatch(crow::Response &res, const crow::Request &req,
1635 const std::vector<std::string> &params) override
1636 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001637 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001638 if (params.size() != 1)
1639 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001640 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001641 return;
1642 }
1643
Ed Tanous4a0cb852018-10-15 07:55:04 -07001644 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001645
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001646 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301647 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001648 std::optional<std::string> ipv6DefaultGateway;
Ravi Tejad1d50812019-06-23 16:20:27 -05001649 std::optional<nlohmann::json> ipv4StaticAddresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001650 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001651 std::optional<std::vector<std::string>> staticNameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001652 std::optional<nlohmann::json> dhcpv4;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001653
Johnathan Mantey01784822019-06-18 12:44:21 -07001654 if (!json_util::readJson(req, res, "HostName", hostname,
1655 "IPv4StaticAddresses", ipv4StaticAddresses,
1656 "MACAddress", macAddress, "StaticNameServers",
1657 staticNameServers, "IPv6DefaultGateway",
1658 ipv6DefaultGateway, "IPv6StaticAddresses",
1659 ipv6StaticAddresses, "DHCPv4", dhcpv4))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 {
1661 return;
1662 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301663
Jennifer Leeda131a92019-04-24 15:13:55 -07001664 if (dhcpv4)
1665 {
1666 handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1667 }
1668
Johnathan Mantey01784822019-06-18 12:44:21 -07001669 // Get single eth interface data, and call the below callback for
1670 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001671 getEthernetIfaceData(
1672 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001673 [this, asyncResp, iface_id, hostname = std::move(hostname),
1674 macAddress = std::move(macAddress),
Ravi Tejad1d50812019-06-23 16:20:27 -05001675 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001676 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001677 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
Johnathan Mantey01784822019-06-18 12:44:21 -07001678 staticNameServers = std::move(staticNameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001679 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001680 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001681 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 if (!success)
1683 {
1684 // ... otherwise return error
1685 // TODO(Pawel)consider distinguish between non existing
1686 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001687 messages::resourceNotFound(asyncResp->res,
1688 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001689 return;
1690 }
1691
Ed Tanous0627a2c2018-11-29 17:09:23 -08001692 if (hostname)
1693 {
1694 handleHostnamePatch(*hostname, asyncResp);
1695 }
1696
Ratan Guptad5776652019-03-03 08:47:22 +05301697 if (macAddress)
1698 {
1699 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1700 }
1701
Ravi Tejad1d50812019-06-23 16:20:27 -05001702 if (ipv4StaticAddresses)
1703 {
Ed Tanous537174c2018-12-10 15:09:31 -08001704 // TODO(ed) for some reason the capture of ipv4Addresses
Johnathan Mantey01784822019-06-18 12:44:21 -07001705 // above is returning a const value, not a non-const
1706 // value. This doesn't really work for us, as we need to
1707 // be able to efficiently move out the intermedia
1708 // nlohmann::json objects. This makes a copy of the
1709 // structure, and operates on that, but could be done
1710 // more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001711 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
Johnathan Mantey01784822019-06-18 12:44:21 -07001712 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001713 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001714 }
1715
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001716 if (staticNameServers)
1717 {
1718 handleStaticNameServersPatch(iface_id, *staticNameServers,
1719 asyncResp);
1720 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001721
1722 if (ipv6DefaultGateway)
1723 {
1724 messages::propertyNotWritable(asyncResp->res,
1725 "IPv6DefaultGateway");
1726 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001727
1728 if (ipv6StaticAddresses)
1729 {
1730 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1731 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
Johnathan Mantey01784822019-06-18 12:44:21 -07001732 ipv6Data, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001733 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 });
1735 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001736};
1737
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001738/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001739 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1740 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001741 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742class VlanNetworkInterface : public Node
1743{
1744 public:
1745 /*
1746 * Default Constructor
1747 */
1748 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001749 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001750 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001751 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001752 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001753 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001754 entityPrivileges = {
1755 {boost::beast::http::verb::get, {{"Login"}}},
1756 {boost::beast::http::verb::head, {{"Login"}}},
1757 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1758 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1759 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1760 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001761 }
1762
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001764 void parseInterfaceData(
1765 nlohmann::json &json_response, const std::string &parent_iface_id,
1766 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001767 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001768 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001769 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001771 json_response["Id"] = iface_id;
1772 json_response["@odata.id"] =
1773 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1774 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775
Ed Tanous4a0cb852018-10-15 07:55:04 -07001776 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001777 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001778 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001779 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001780 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001781 }
1782
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001783 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 {
1785 if (!boost::starts_with(iface, parent + "_"))
1786 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001787 return false;
1788 }
1789 else
1790 {
1791 return true;
1792 }
1793 }
1794
1795 /**
1796 * Functions triggers appropriate requests on DBus
1797 */
1798 void doGet(crow::Response &res, const crow::Request &req,
1799 const std::vector<std::string> &params) override
1800 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001801 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1802 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1804 // Check if there is required param, truly entering this shall be
1805 // impossible.
1806 if (params.size() != 2)
1807 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001808 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001810 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001812
Ed Tanous4a0cb852018-10-15 07:55:04 -07001813 const std::string &parent_iface_id = params[0];
1814 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001815 res.jsonValue["@odata.type"] =
1816 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1817 res.jsonValue["@odata.context"] =
Johnathan Mantey01784822019-06-18 12:44:21 -07001818 "/redfish/v1/"
1819 "$metadata#VLanNetworkInterface.VLanNetworkInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001820 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001821
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001822 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001823 {
1824 return;
1825 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001826
Johnathan Mantey01784822019-06-18 12:44:21 -07001827 // Get single eth interface data, and call the below callback for
1828 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001829 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001830 params[1],
1831 [this, asyncResp, parent_iface_id{std::string(params[0])},
1832 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001833 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001834 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001835 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001836 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001838 parseInterfaceData(asyncResp->res.jsonValue,
1839 parent_iface_id, iface_id, ethData,
Johnathan Mantey01784822019-06-18 12:44:21 -07001840 ipv4Data, ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001841 }
1842 else
1843 {
1844 // ... otherwise return error
1845 // TODO(Pawel)consider distinguish between non existing
1846 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001847 messages::resourceNotFound(
1848 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001851 }
1852
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 void doPatch(crow::Response &res, const crow::Request &req,
1854 const std::vector<std::string> &params) override
1855 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001856 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001857 if (params.size() != 2)
1858 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001859 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001860 return;
1861 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001862
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 const std::string &parentIfaceId = params[0];
1864 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001865
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001866 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001868 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1869 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 return;
1871 }
1872
Ed Tanous0627a2c2018-11-29 17:09:23 -08001873 bool vlanEnable = false;
1874 uint64_t vlanId = 0;
1875
1876 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1877 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 {
1879 return;
1880 }
1881
Johnathan Mantey01784822019-06-18 12:44:21 -07001882 // Get single eth interface data, and call the below callback for
1883 // JSON preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001884 getEthernetIfaceData(
1885 params[1],
Ed Tanous271584a2019-07-09 16:24:22 -07001886 [asyncResp, parentIfaceId{std::string(params[0])},
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001887 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1888 const bool &success, const EthernetInterfaceData &ethData,
1889 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001890 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001891 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05001892 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001893 auto callback =
1894 [asyncResp](const boost::system::error_code ec) {
1895 if (ec)
1896 {
1897 messages::internalError(asyncResp->res);
1898 }
1899 };
1900
1901 if (vlanEnable == true)
1902 {
1903 crow::connections::systemBus->async_method_call(
1904 std::move(callback), "xyz.openbmc_project.Network",
1905 "/xyz/openbmc_project/network/" + ifaceId,
1906 "org.freedesktop.DBus.Properties", "Set",
1907 "xyz.openbmc_project.Network.VLAN", "Id",
1908 std::variant<uint32_t>(vlanId));
1909 }
1910 else
1911 {
1912 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1913 "vlan interface";
1914 crow::connections::systemBus->async_method_call(
1915 std::move(callback), "xyz.openbmc_project.Network",
1916 std::string("/xyz/openbmc_project/network/") +
1917 ifaceId,
1918 "xyz.openbmc_project.Object.Delete", "Delete");
1919 }
Sunitha Harish08244d02019-04-01 03:57:25 -05001920 }
1921 else
1922 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001923 // TODO(Pawel)consider distinguish between non existing
1924 // object, and other errors
1925 messages::resourceNotFound(
1926 asyncResp->res, "VLAN Network Interface", ifaceId);
1927 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05001928 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001929 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001930 }
1931
1932 void doDelete(crow::Response &res, const crow::Request &req,
1933 const std::vector<std::string> &params) override
1934 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001935 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001936 if (params.size() != 2)
1937 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001938 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 return;
1940 }
1941
1942 const std::string &parentIfaceId = params[0];
1943 const std::string &ifaceId = params[1];
1944
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001945 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001946 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001947 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1948 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001949 return;
1950 }
1951
Johnathan Mantey01784822019-06-18 12:44:21 -07001952 // Get single eth interface data, and call the below callback for
1953 // JSON preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001954 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001955 params[1],
Ed Tanous271584a2019-07-09 16:24:22 -07001956 [asyncResp, parentIfaceId{std::string(params[0])},
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001957 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001958 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001959 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001960 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001961 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001962 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001963 auto callback =
1964 [asyncResp](const boost::system::error_code ec) {
1965 if (ec)
1966 {
1967 messages::internalError(asyncResp->res);
1968 }
1969 };
1970 crow::connections::systemBus->async_method_call(
1971 std::move(callback), "xyz.openbmc_project.Network",
1972 std::string("/xyz/openbmc_project/network/") + ifaceId,
1973 "xyz.openbmc_project.Object.Delete", "Delete");
1974 }
1975 else
1976 {
1977 // ... otherwise return error
1978 // TODO(Pawel)consider distinguish between non existing
1979 // object, and other errors
1980 messages::resourceNotFound(
1981 asyncResp->res, "VLAN Network Interface", ifaceId);
1982 }
1983 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001984 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001985};
1986
1987/**
1988 * VlanNetworkInterfaceCollection derived class for delivering
1989 * VLANNetworkInterface Collection Schema
1990 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001991class VlanNetworkInterfaceCollection : public Node
1992{
1993 public:
1994 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001995 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001996 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1997 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001998 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001999 entityPrivileges = {
2000 {boost::beast::http::verb::get, {{"Login"}}},
2001 {boost::beast::http::verb::head, {{"Login"}}},
2002 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2003 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2004 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2005 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002006 }
2007
Ed Tanous1abe55e2018-09-05 08:30:59 -07002008 private:
2009 /**
2010 * Functions triggers appropriate requests on DBus
2011 */
2012 void doGet(crow::Response &res, const crow::Request &req,
2013 const std::vector<std::string> &params) override
2014 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002015 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016 if (params.size() != 1)
2017 {
2018 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002019 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002020 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002021 }
2022
Ed Tanous4a0cb852018-10-15 07:55:04 -07002023 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002024
Ed Tanous4a0cb852018-10-15 07:55:04 -07002025 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002026 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002027 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002028 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002029 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002030 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002031 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002032 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002033 messages::internalError(asyncResp->res);
2034 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002035 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002036
2037 if (iface_list.find(rootInterfaceName) == iface_list.end())
2038 {
2039 messages::resourceNotFound(asyncResp->res,
2040 "VLanNetworkInterfaceCollection",
2041 rootInterfaceName);
2042 return;
2043 }
2044
Ed Tanous0f74e642018-11-12 15:17:05 -08002045 asyncResp->res.jsonValue["@odata.type"] =
2046 "#VLanNetworkInterfaceCollection."
2047 "VLanNetworkInterfaceCollection";
2048 asyncResp->res.jsonValue["@odata.context"] =
2049 "/redfish/v1/$metadata"
2050 "#VLanNetworkInterfaceCollection."
2051 "VLanNetworkInterfaceCollection";
2052 asyncResp->res.jsonValue["Name"] =
2053 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002054
Jason M. Billsf12894f2018-10-09 12:45:45 -07002055 nlohmann::json iface_array = nlohmann::json::array();
2056
2057 for (const std::string &iface_item : iface_list)
2058 {
2059 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2060 {
2061 iface_array.push_back(
2062 {{"@odata.id",
2063 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2064 rootInterfaceName + "/VLANs/" + iface_item}});
2065 }
2066 }
2067
Jason M. Billsf12894f2018-10-09 12:45:45 -07002068 asyncResp->res.jsonValue["Members@odata.count"] =
2069 iface_array.size();
2070 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2071 asyncResp->res.jsonValue["@odata.id"] =
2072 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2073 rootInterfaceName + "/VLANs";
2074 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002075 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002076
Ed Tanous1abe55e2018-09-05 08:30:59 -07002077 void doPost(crow::Response &res, const crow::Request &req,
2078 const std::vector<std::string> &params) override
2079 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002080 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002081 if (params.size() != 1)
2082 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002083 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002084 return;
2085 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002086 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002087 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002088 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2089 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002090 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002091 return;
2092 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002093 // Need both vlanId and vlanEnable to service this request
2094 if (!vlanId)
2095 {
2096 messages::propertyMissing(asyncResp->res, "VLANId");
2097 }
2098 if (!vlanEnable)
2099 {
2100 messages::propertyMissing(asyncResp->res, "VLANEnable");
2101 }
Ed Tanous271584a2019-07-09 16:24:22 -07002102 if (static_cast<bool>(vlanId) ^ vlanEnable)
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002103 {
2104 return;
2105 }
2106
Ed Tanous4a0cb852018-10-15 07:55:04 -07002107 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002108 auto callback = [asyncResp](const boost::system::error_code ec) {
2109 if (ec)
2110 {
2111 // TODO(ed) make more consistent error messages based on
2112 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002113 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002114 return;
2115 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002116 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002117 };
2118 crow::connections::systemBus->async_method_call(
2119 std::move(callback), "xyz.openbmc_project.Network",
2120 "/xyz/openbmc_project/network",
2121 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002122 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002123 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002124};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002125} // namespace redfish