blob: 71ad624f904007627ab9af03e64f2c5c56480ce1 [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/**
74 * Structure for keeping basic single Ethernet Interface information
75 * available from DBus
76 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070077struct EthernetInterfaceData
78{
Ed Tanous4a0cb852018-10-15 07:55:04 -070079 uint32_t speed;
80 bool auto_neg;
manojkiraneda2a133282019-02-19 13:09:43 +053081 bool DHCPEnabled;
Ed Tanous4a0cb852018-10-15 07:55:04 -070082 std::string hostname;
83 std::string default_gateway;
84 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -050085 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -080086 std::vector<std::string> nameservers;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010087};
88
Ed Tanous4a0cb852018-10-15 07:55:04 -070089// Helper function that changes bits netmask notation (i.e. /24)
90// into full dot notation
91inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -070092{
Ed Tanous4a0cb852018-10-15 07:55:04 -070093 uint32_t value = 0xffffffff << (32 - bits);
94 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
95 std::to_string((value >> 16) & 0xff) + "." +
96 std::to_string((value >> 8) & 0xff) + "." +
97 std::to_string(value & 0xff);
98 return netmask;
99}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100100
Ed Tanous4a0cb852018-10-15 07:55:04 -0700101inline std::string
102 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
103 bool isIPv4)
104{
105 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700107 return "Static";
108 }
109 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
110 {
111 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700113 return "IPv4LinkLocal";
114 }
115 else
116 {
117 return "LinkLocal";
118 }
119 }
120 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
121 {
122 if (isIPv4)
123 {
124 return "DHCP";
125 }
126 else
127 {
128 return "DHCPv6";
129 }
130 }
131 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
132 {
133 return "SLAAC";
134 }
135 return "";
136}
137
138inline std::string
139 translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
140{
141 if (inputOrigin == "Static")
142 {
143 return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
144 }
145 if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
146 {
147 return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
148 }
149 if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
150 {
151 return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
152 }
153 if (inputOrigin == "SLAAC")
154 {
155 return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
156 }
157 return "";
158}
159
160inline void extractEthernetInterfaceData(const std::string &ethiface_id,
161 const GetManagedObjects &dbus_data,
162 EthernetInterfaceData &ethData)
163{
164 for (const auto &objpath : dbus_data)
165 {
Ed Tanous029573d2019-02-01 10:57:49 -0800166 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700167 {
Ed Tanous029573d2019-02-01 10:57:49 -0800168 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700170 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700172 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700174 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700176 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800177 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700178 if (mac != nullptr)
179 {
180 ethData.mac_address = *mac;
181 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700182 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700183 }
184 }
185 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
186 {
187 for (const auto &propertyPair : ifacePair.second)
188 {
189 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700190 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800191 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800192 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700193 if (id != nullptr)
194 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500195 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700196 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700198 }
199 }
200 else if (ifacePair.first ==
201 "xyz.openbmc_project.Network.EthernetInterface")
202 {
203 for (const auto &propertyPair : ifacePair.second)
204 {
205 if (propertyPair.first == "AutoNeg")
206 {
207 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800208 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700209 if (auto_neg != nullptr)
210 {
211 ethData.auto_neg = *auto_neg;
212 }
213 }
214 else if (propertyPair.first == "Speed")
215 {
216 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800217 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700218 if (speed != nullptr)
219 {
220 ethData.speed = *speed;
221 }
222 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500223 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700224 {
Ed Tanous029573d2019-02-01 10:57:49 -0800225 const std::vector<std::string> *nameservers =
226 sdbusplus::message::variant_ns::get_if<
227 std::vector<std::string>>(
228 &propertyPair.second);
229 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700230 {
Ed Tanous029573d2019-02-01 10:57:49 -0800231 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700232 }
233 }
manojkiraneda2a133282019-02-19 13:09:43 +0530234 else if (propertyPair.first == "DHCPEnabled")
235 {
236 const bool *DHCPEnabled =
237 std::get_if<bool>(&propertyPair.second);
238 if (DHCPEnabled != nullptr)
239 {
240 ethData.DHCPEnabled = *DHCPEnabled;
241 }
242 }
Ed Tanous029573d2019-02-01 10:57:49 -0800243 }
244 }
245 }
246 // System configuration shows up in the global namespace, so no need
247 // to check eth number
248 if (ifacePair.first ==
249 "xyz.openbmc_project.Network.SystemConfiguration")
250 {
251 for (const auto &propertyPair : ifacePair.second)
252 {
253 if (propertyPair.first == "HostName")
254 {
255 const std::string *hostname =
256 sdbusplus::message::variant_ns::get_if<std::string>(
257 &propertyPair.second);
258 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700259 {
Ed Tanous029573d2019-02-01 10:57:49 -0800260 ethData.hostname = *hostname;
261 }
262 }
263 else if (propertyPair.first == "DefaultGateway")
264 {
265 const std::string *defaultGateway =
266 sdbusplus::message::variant_ns::get_if<std::string>(
267 &propertyPair.second);
268 if (defaultGateway != nullptr)
269 {
270 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700271 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 }
273 }
274 }
275 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700277}
278
279// Helper function that extracts data for single ethernet ipv4 address
280inline void
281 extractIPData(const std::string &ethiface_id,
282 const GetManagedObjects &dbus_data,
283 boost::container::flat_set<IPv4AddressData> &ipv4_config)
284{
285 const std::string ipv4PathStart =
286 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
287
288 // Since there might be several IPv4 configurations aligned with
289 // single ethernet interface, loop over all of them
290 for (const auto &objpath : dbus_data)
291 {
292 // Check if proper pattern for object path appears
293 if (boost::starts_with(objpath.first.str, ipv4PathStart))
294 {
295 for (auto &interface : objpath.second)
296 {
297 if (interface.first == "xyz.openbmc_project.Network.IP")
298 {
299 // Instance IPv4AddressData structure, and set as
300 // appropriate
301 std::pair<
302 boost::container::flat_set<IPv4AddressData>::iterator,
303 bool>
304 it = ipv4_config.insert(
Ed Tanousb01bf292019-03-25 19:25:26 +0000305 {objpath.first.str.substr(ipv4PathStart.size())});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700306 IPv4AddressData &ipv4_address = *it.first;
307 for (auto &property : interface.second)
308 {
309 if (property.first == "Address")
310 {
311 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800312 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700313 if (address != nullptr)
314 {
315 ipv4_address.address = *address;
316 }
317 }
318 else if (property.first == "Gateway")
319 {
320 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800321 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700322 if (gateway != nullptr)
323 {
324 ipv4_address.gateway = *gateway;
325 }
326 }
327 else if (property.first == "Origin")
328 {
329 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800330 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700331 if (origin != nullptr)
332 {
333 ipv4_address.origin =
334 translateAddressOriginDbusToRedfish(*origin,
335 true);
336 }
337 }
338 else if (property.first == "PrefixLength")
339 {
340 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800341 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700342 if (mask != nullptr)
343 {
344 // convert it to the string
345 ipv4_address.netmask = getNetmask(*mask);
346 }
347 }
348 else
349 {
350 BMCWEB_LOG_ERROR
351 << "Got extra property: " << property.first
352 << " on the " << objpath.first.str << " object";
353 }
354 }
355 // Check if given address is local, or global
356 ipv4_address.linktype =
357 boost::starts_with(ipv4_address.address, "169.254.")
358 ? LinkType::Global
359 : LinkType::Local;
360 }
361 }
362 }
363 }
364}
365
366/**
367 * @brief Sets given Id on the given VLAN interface through D-Bus
368 *
369 * @param[in] ifaceId Id of VLAN interface that should be modified
370 * @param[in] inputVlanId New ID of the VLAN
371 * @param[in] callback Function that will be called after the operation
372 *
373 * @return None.
374 */
375template <typename CallbackFunc>
376void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
377 CallbackFunc &&callback)
378{
379 crow::connections::systemBus->async_method_call(
380 callback, "xyz.openbmc_project.Network",
381 std::string("/xyz/openbmc_project/network/") + ifaceId,
382 "org.freedesktop.DBus.Properties", "Set",
383 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800384 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700385}
386
387/**
388 * @brief Helper function that verifies IP address to check if it is in
389 * proper format. If bits pointer is provided, also calculates active
390 * bit count for Subnet Mask.
391 *
392 * @param[in] ip IP that will be verified
393 * @param[out] bits Calculated mask in bits notation
394 *
395 * @return true in case of success, false otherwise
396 */
397inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
398 uint8_t *bits = nullptr)
399{
400 std::vector<std::string> bytesInMask;
401
402 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700403
404 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700405 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700407 return false;
408 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409
Ed Tanous4a0cb852018-10-15 07:55:04 -0700410 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700412 *bits = 0;
413 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414
Ed Tanous4a0cb852018-10-15 07:55:04 -0700415 char *endPtr;
416 long previousValue = 255;
417 bool firstZeroInByteHit;
418 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700420 if (byte.empty())
421 {
422 return false;
423 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424
Ed Tanous4a0cb852018-10-15 07:55:04 -0700425 // Use strtol instead of stroi to avoid exceptions
426 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427
Ed Tanous4a0cb852018-10-15 07:55:04 -0700428 // endPtr should point to the end of the string, otherwise given string
429 // is not 100% number
430 if (*endPtr != '\0')
431 {
432 return false;
433 }
434
435 // Value should be contained in byte
436 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 {
438 return false;
439 }
440
441 if (bits != nullptr)
442 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700443 // Mask has to be continuous between bytes
444 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 {
446 return false;
447 }
448
Ed Tanous4a0cb852018-10-15 07:55:04 -0700449 // Mask has to be continuous inside bytes
450 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451
Ed Tanous4a0cb852018-10-15 07:55:04 -0700452 // Count bits
453 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700455 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700456 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700457 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700459 // Continuity not preserved
460 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 }
462 else
463 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700464 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465 }
466 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467 else
468 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700469 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700471 }
472 }
473
474 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 }
476
Ed Tanous4a0cb852018-10-15 07:55:04 -0700477 return true;
478}
479
480/**
Ed Tanousb01bf292019-03-25 19:25:26 +0000481 * @brief Changes IPv4 address type property (Address, Gateway)
482 *
483 * @param[in] ifaceId Id of interface whose IP should be modified
484 * @param[in] ipIdx Index of IP in input array that should be modified
485 * @param[in] ipHash DBus Hash id of modified IP
486 * @param[in] name Name of field in JSON representation
487 * @param[in] newValue New value that should be written
488 * @param[io] asyncResp Response object that will be returned to client
489 *
490 * @return true if give IP is valid and has been sent do D-Bus, false
491 * otherwise
492 */
493inline void changeIPv4AddressProperty(
494 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
495 const std::string &name, const std::string &newValue,
496 const std::shared_ptr<AsyncResp> asyncResp)
497{
498 auto callback = [asyncResp, ipIdx, name{std::string(name)},
499 newValue{std::move(newValue)}](
500 const boost::system::error_code ec) {
501 if (ec)
502 {
503 messages::internalError(asyncResp->res);
504 }
505 else
506 {
507 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
508 }
509 };
510
511 crow::connections::systemBus->async_method_call(
512 std::move(callback), "xyz.openbmc_project.Network",
513 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
514 "org.freedesktop.DBus.Properties", "Set",
515 "xyz.openbmc_project.Network.IP", name,
516 std::variant<std::string>(newValue));
517}
518
519/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700520 * @brief Changes IPv4 address origin property
521 *
522 * @param[in] ifaceId Id of interface whose IP should be modified
523 * @param[in] ipIdx Index of IP in input array that should be
524 * modified
525 * @param[in] ipHash DBus Hash id of modified IP
526 * @param[in] newValue New value in Redfish format
527 * @param[in] newValueDbus New value in D-Bus format
528 * @param[io] asyncResp Response object that will be returned to client
529 *
530 * @return true if give IP is valid and has been sent do D-Bus, false
531 * otherwise
532 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000533inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700534 const std::string &ipHash,
535 const std::string &newValue,
536 const std::string &newValueDbus,
537 const std::shared_ptr<AsyncResp> asyncResp)
538{
539 auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
540 const boost::system::error_code ec) {
541 if (ec)
542 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800543 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700544 }
545 else
546 {
547 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
548 newValue;
549 }
550 };
551
552 crow::connections::systemBus->async_method_call(
553 std::move(callback), "xyz.openbmc_project.Network",
554 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
555 "org.freedesktop.DBus.Properties", "Set",
556 "xyz.openbmc_project.Network.IP", "Origin",
Ed Tanousabf2add2019-01-22 16:40:12 -0800557 std::variant<std::string>(newValueDbus));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700558}
559
560/**
561 * @brief Modifies SubnetMask for given IP
562 *
563 * @param[in] ifaceId Id of interface whose IP should be modified
564 * @param[in] ipIdx Index of IP in input array that should be
565 * modified
566 * @param[in] ipHash DBus Hash id of modified IP
567 * @param[in] newValueStr Mask in dot notation as string
568 * @param[in] newValue Mask as PrefixLength in bitcount
569 * @param[io] asyncResp Response object that will be returned to client
570 *
571 * @return None
572 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000573inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700574 const std::string &ipHash,
575 const std::string &newValueStr,
576 uint8_t &newValue,
577 std::shared_ptr<AsyncResp> asyncResp)
578{
579 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
580 const boost::system::error_code ec) {
581 if (ec)
582 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800583 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700584 }
585 else
586 {
587 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
588 newValueStr;
589 }
590 };
591
592 crow::connections::systemBus->async_method_call(
593 std::move(callback), "xyz.openbmc_project.Network",
594 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
595 "org.freedesktop.DBus.Properties", "Set",
596 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800597 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700598}
599
600/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700601 * @brief Deletes given IPv4
602 *
603 * @param[in] ifaceId Id of interface whose IP should be deleted
604 * @param[in] ipIdx Index of IP in input array that should be deleted
605 * @param[in] ipHash DBus Hash id of IP that should be deleted
606 * @param[io] asyncResp Response object that will be returned to client
607 *
608 * @return None
609 */
610inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
611 unsigned int ipIdx,
612 const std::shared_ptr<AsyncResp> asyncResp)
613{
614 crow::connections::systemBus->async_method_call(
615 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 if (ec)
617 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800618 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100619 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700620 else
621 {
622 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
623 }
624 },
625 "xyz.openbmc_project.Network",
626 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
627 "xyz.openbmc_project.Object.Delete", "Delete");
628}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629
Ed Tanous4a0cb852018-10-15 07:55:04 -0700630/**
631 * @brief Creates IPv4 with given data
632 *
633 * @param[in] ifaceId Id of interface whose IP should be deleted
634 * @param[in] ipIdx Index of IP in input array that should be deleted
635 * @param[in] ipHash DBus Hash id of IP that should be deleted
636 * @param[io] asyncResp Response object that will be returned to client
637 *
638 * @return None
639 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000640inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
641 uint8_t subnetMask, const std::string &gateway,
642 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700643 std::shared_ptr<AsyncResp> asyncResp)
644{
Ed Tanous43b761d2019-02-13 20:10:56 -0800645 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700646 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800648 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 };
651
Ed Tanous4a0cb852018-10-15 07:55:04 -0700652 crow::connections::systemBus->async_method_call(
653 std::move(createIpHandler), "xyz.openbmc_project.Network",
654 "/xyz/openbmc_project/network/" + ifaceId,
655 "xyz.openbmc_project.Network.IP.Create", "IP",
656 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
657 gateway);
658}
manojkiraneda2a133282019-02-19 13:09:43 +0530659using GetAllPropertiesType =
660 boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
661
662inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
663{
664 auto getConfig = [asyncResp](const boost::system::error_code error_code,
665 const GetAllPropertiesType &dbus_data) {
666 if (error_code)
667 {
668 BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
669 messages::internalError(asyncResp->res);
670 return;
671 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500672 nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
manojkiraneda2a133282019-02-19 13:09:43 +0530673 for (const auto &property : dbus_data)
674 {
675 auto value =
676 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
677
678 if (value == nullptr)
679 {
680 continue;
681 }
682 if (property.first == "DNSEnabled")
683 {
684 DHCPConfigTypeJson["UseDNSServers"] = *value;
685 }
686 else if (property.first == "HostNameEnabled")
687 {
688 DHCPConfigTypeJson["UseDomainName"] = *value;
689 }
690 else if (property.first == "NTPEnabled")
691 {
692 DHCPConfigTypeJson["UseNTPServers"] = *value;
693 }
694 }
695 };
696 crow::connections::systemBus->async_method_call(
697 std::move(getConfig), "xyz.openbmc_project.Network",
698 "/xyz/openbmc_project/network/config/dhcp",
699 "org.freedesktop.DBus.Properties", "GetAll",
700 "xyz.openbmc_project.Network.DHCPConfiguration");
701}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702
Ed Tanous4a0cb852018-10-15 07:55:04 -0700703/**
704 * Function that retrieves all properties for given Ethernet Interface
705 * Object
706 * from EntityManager Network Manager
707 * @param ethiface_id a eth interface id to query on DBus
708 * @param callback a function that shall be called to convert Dbus output
709 * into JSON
710 */
711template <typename CallbackFunc>
712void getEthernetIfaceData(const std::string &ethiface_id,
713 CallbackFunc &&callback)
714{
715 crow::connections::systemBus->async_method_call(
716 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
717 const boost::system::error_code error_code,
718 const GetManagedObjects &resp) {
719 EthernetInterfaceData ethData{};
720 boost::container::flat_set<IPv4AddressData> ipv4Data;
721
722 if (error_code)
723 {
724 callback(false, ethData, ipv4Data);
725 return;
726 }
727
728 extractEthernetInterfaceData(ethiface_id, resp, ethData);
729 extractIPData(ethiface_id, resp, ipv4Data);
730
731 // Fix global GW
732 for (IPv4AddressData &ipv4 : ipv4Data)
733 {
734 if ((ipv4.linktype == LinkType::Global) &&
735 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700737 ipv4.gateway = ethData.default_gateway;
738 }
739 }
740
741 // Finally make a callback with usefull data
742 callback(true, ethData, ipv4Data);
743 },
744 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
745 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
746};
747
748/**
749 * Function that retrieves all Ethernet Interfaces available through Network
750 * Manager
751 * @param callback a function that shall be called to convert Dbus output
752 * into JSON.
753 */
754template <typename CallbackFunc>
755void getEthernetIfaceList(CallbackFunc &&callback)
756{
757 crow::connections::systemBus->async_method_call(
758 [callback{std::move(callback)}](
759 const boost::system::error_code error_code,
760 GetManagedObjects &resp) {
761 // Callback requires vector<string> to retrieve all available
762 // ethernet interfaces
763 std::vector<std::string> iface_list;
764 iface_list.reserve(resp.size());
765 if (error_code)
766 {
767 callback(false, iface_list);
768 return;
769 }
770
771 // Iterate over all retrieved ObjectPaths.
772 for (const auto &objpath : resp)
773 {
774 // And all interfaces available for certain ObjectPath.
775 for (const auto &interface : objpath.second)
776 {
777 // If interface is
778 // xyz.openbmc_project.Network.EthernetInterface, this is
779 // what we're looking for.
780 if (interface.first ==
781 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700783 // Cut out everyting until last "/", ...
784 const std::string &iface_id = objpath.first.str;
785 std::size_t last_pos = iface_id.rfind("/");
786 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700788 // and put it into output vector.
789 iface_list.emplace_back(
790 iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 }
792 }
793 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700794 }
795 // Finally make a callback with useful data
796 callback(true, iface_list);
797 },
798 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
799 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100800};
801
802/**
803 * EthernetCollection derived class for delivering Ethernet Collection Schema
804 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805class EthernetCollection : public Node
806{
807 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700808 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700810 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 entityPrivileges = {
813 {boost::beast::http::verb::get, {{"Login"}}},
814 {boost::beast::http::verb::head, {{"Login"}}},
815 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
816 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
817 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
818 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
819 }
820
821 private:
822 /**
823 * Functions triggers appropriate requests on DBus
824 */
825 void doGet(crow::Response &res, const crow::Request &req,
826 const std::vector<std::string> &params) override
827 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800828 res.jsonValue["@odata.type"] =
829 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
830 res.jsonValue["@odata.context"] =
831 "/redfish/v1/"
832 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
833 res.jsonValue["@odata.id"] =
834 "/redfish/v1/Managers/bmc/EthernetInterfaces";
835 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
836 res.jsonValue["Description"] =
837 "Collection of EthernetInterfaces for this Manager";
838
Ed Tanous4a0cb852018-10-15 07:55:04 -0700839 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700841 getEthernetIfaceList(
842 [&res](const bool &success,
843 const std::vector<std::string> &iface_list) {
844 if (!success)
845 {
846 messages::internalError(res);
847 res.end();
848 return;
849 }
850
851 nlohmann::json &iface_array = res.jsonValue["Members"];
852 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500853 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -0700854 for (const std::string &iface_item : iface_list)
855 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500856 std::size_t found = iface_item.find(tag);
857 if (found == std::string::npos)
858 {
859 iface_array.push_back(
860 {{"@odata.id",
861 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
862 iface_item}});
863 }
Jason M. Billsf12894f2018-10-09 12:45:45 -0700864 }
865
866 res.jsonValue["Members@odata.count"] = iface_array.size();
867 res.jsonValue["@odata.id"] =
868 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 res.end();
Jason M. Billsf12894f2018-10-09 12:45:45 -0700870 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700871 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100872};
873
874/**
875 * EthernetInterface derived class for delivering Ethernet Schema
876 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877class EthernetInterface : public Node
878{
879 public:
880 /*
881 * Default Constructor
882 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700883 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700885 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 std::string())
887 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 entityPrivileges = {
889 {boost::beast::http::verb::get, {{"Login"}}},
890 {boost::beast::http::verb::head, {{"Login"}}},
891 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
892 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
893 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
894 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200895 }
896
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800898 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700899 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800901 asyncResp->res.jsonValue["HostName"] = hostname;
902 crow::connections::systemBus->async_method_call(
903 [asyncResp](const boost::system::error_code ec) {
904 if (ec)
905 {
906 messages::internalError(asyncResp->res);
907 }
908 },
909 "xyz.openbmc_project.Network",
910 "/xyz/openbmc_project/network/config",
911 "org.freedesktop.DBus.Properties", "Set",
912 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -0800913 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 }
915
Ratan Guptad5776652019-03-03 08:47:22 +0530916 void handleMACAddressPatch(const std::string &ifaceId,
917 const std::string &macAddress,
918 const std::shared_ptr<AsyncResp> &asyncResp)
919 {
920 crow::connections::systemBus->async_method_call(
921 [asyncResp, macAddress](const boost::system::error_code ec) {
922 if (ec)
923 {
924 messages::internalError(asyncResp->res);
925 return;
926 }
927 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
928 },
929 "xyz.openbmc_project.Network",
930 "/xyz/openbmc_project/network/" + ifaceId,
931 "org.freedesktop.DBus.Properties", "Set",
932 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
933 std::variant<std::string>(macAddress));
934 }
935
Ed Tanous4a0cb852018-10-15 07:55:04 -0700936 void handleIPv4Patch(
Ratan Guptaf476acb2019-03-02 16:46:57 +0530937 const std::string &ifaceId, nlohmann::json &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700938 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
939 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 {
Ratan Guptaf476acb2019-03-02 16:46:57 +0530941 if (!input.is_array())
942 {
943 messages::propertyValueTypeError(asyncResp->res, input.dump(),
944 "IPv4Addresses");
945 return;
946 }
947
Ed Tanous4a0cb852018-10-15 07:55:04 -0700948 int entryIdx = 0;
949 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
950 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -0800951 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700953 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800954 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955
Ratan Guptaf476acb2019-03-02 16:46:57 +0530956 if (thisJson.is_null())
957 {
958 if (thisData != ipv4Data.end())
959 {
960 deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
961 thisData++;
962 }
963 else
964 {
965 messages::propertyValueFormatError(
966 asyncResp->res, input.dump(), pathString);
967 return;
968 // TODO(ratagupt) Not sure about the property where value is
969 // list and if unable to update one of the
970 // list value then should we proceed further or
971 // break there, would ask in the redfish forum
972 // till then we stop processing the next list item.
973 }
974 entryIdx++;
975 continue; // not an error as per the redfish spec.
976 }
977
Ratan Gupta9474b372019-03-01 15:13:37 +0530978 if (thisJson.empty())
979 {
980 if (thisData != ipv4Data.end())
981 {
982 thisData++;
983 }
984 else
985 {
986 messages::propertyMissing(asyncResp->res,
987 pathString + "/Address");
988 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +0530989 // TODO(ratagupt) Not sure about the property where value is
Ratan Gupta9474b372019-03-01 15:13:37 +0530990 // list and if unable to update one of the
991 // list value then should we proceed further or
992 // break there, would ask in the redfish forum
993 // till then we stop processing the next list item.
994 }
995 entryIdx++;
996 continue; // not an error as per the redfish spec.
997 }
998
Ed Tanous537174c2018-12-10 15:09:31 -0800999 std::optional<std::string> address;
1000 std::optional<std::string> addressOrigin;
1001 std::optional<std::string> subnetMask;
1002 std::optional<std::string> gateway;
1003
1004 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1005 address, "AddressOrigin", addressOrigin,
1006 "SubnetMask", subnetMask, "Gateway",
1007 gateway))
1008 {
1009 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 }
1011
Ed Tanous537174c2018-12-10 15:09:31 -08001012 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001013 {
Ed Tanous537174c2018-12-10 15:09:31 -08001014 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001015 {
Ed Tanous537174c2018-12-10 15:09:31 -08001016 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001017 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -08001018 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001019 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001020 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001021
Ed Tanous537174c2018-12-10 15:09:31 -08001022 uint8_t prefixLength = 0;
1023 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001024 {
Ed Tanous537174c2018-12-10 15:09:31 -08001025 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001026 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001027 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -08001028 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001029 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -08001030 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001031 }
1032 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001033 std::string addressOriginInDBusFormat;
Ed Tanous537174c2018-12-10 15:09:31 -08001034 if (addressOrigin)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001035 {
Ed Tanous537174c2018-12-10 15:09:31 -08001036 // Get Address origin in proper format
1037 addressOriginInDBusFormat =
1038 translateAddressOriginRedfishToDbus(*addressOrigin);
1039 if (addressOriginInDBusFormat.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001040 {
Ed Tanous537174c2018-12-10 15:09:31 -08001041 messages::propertyValueNotInList(
1042 asyncResp->res, *addressOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001043 pathString + "/AddressOrigin");
Ed Tanous537174c2018-12-10 15:09:31 -08001044 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001045 }
1046 }
1047
Ed Tanous537174c2018-12-10 15:09:31 -08001048 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001049 {
Ed Tanous537174c2018-12-10 15:09:31 -08001050 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -07001051 {
Ed Tanous537174c2018-12-10 15:09:31 -08001052 messages::propertyValueFormatError(asyncResp->res, *gateway,
1053 pathString + "/Gateway");
1054 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001055 }
1056 }
1057
Ratan Guptaf476acb2019-03-02 16:46:57 +05301058 // if IP address exist then modify it.
Ed Tanous4a0cb852018-10-15 07:55:04 -07001059 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001060 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301061 // Apply changes
1062 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001063 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301064 auto callback = [asyncResp, entryIdx,
1065 address{std::string(*address)}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001066 const boost::system::error_code ec) {
1067 if (ec)
1068 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001069 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001070 return;
1071 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301072 asyncResp->res
1073 .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1074 std::move(address);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001075 };
Ratan Guptaf476acb2019-03-02 16:46:57 +05301076
Ed Tanous4a0cb852018-10-15 07:55:04 -07001077 crow::connections::systemBus->async_method_call(
1078 std::move(callback), "xyz.openbmc_project.Network",
1079 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1080 thisData->id,
Ratan Guptaf476acb2019-03-02 16:46:57 +05301081 "org.freedesktop.DBus.Properties", "Set",
1082 "xyz.openbmc_project.Network.IP", "Address",
1083 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001084 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301085
1086 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001087 {
Ratan Guptaf476acb2019-03-02 16:46:57 +05301088 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1089 thisData->id, *subnetMask,
1090 prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001091 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301092
1093 if (addressOrigin)
1094 {
1095 changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1096 *addressOrigin, addressOriginInDBusFormat,
1097 asyncResp);
1098 }
1099
1100 if (gateway)
1101 {
1102 auto callback = [asyncResp, entryIdx,
1103 gateway{std::string(*gateway)}](
1104 const boost::system::error_code ec) {
1105 if (ec)
1106 {
1107 messages::internalError(asyncResp->res);
1108 return;
1109 }
1110 asyncResp->res
1111 .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1112 std::move(gateway);
1113 };
1114
1115 crow::connections::systemBus->async_method_call(
1116 std::move(callback), "xyz.openbmc_project.Network",
1117 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1118 thisData->id,
1119 "org.freedesktop.DBus.Properties", "Set",
1120 "xyz.openbmc_project.Network.IP", "Gateway",
1121 std::variant<std::string>(*gateway));
1122 }
1123
Ed Tanous4a0cb852018-10-15 07:55:04 -07001124 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001125 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001126 else
1127 {
1128 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001129 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001130 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001131 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001132 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001133 continue;
1134 }
1135
Ed Tanous537174c2018-12-10 15:09:31 -08001136 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001137 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001138 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001139 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001140 continue;
1141 }
1142
Ed Tanous537174c2018-12-10 15:09:31 -08001143 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001144 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001145 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001146 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001147 continue;
1148 }
1149
Ed Tanousb01bf292019-03-25 19:25:26 +00001150 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1151 asyncResp);
Ratan Gupta95897b22019-03-07 18:25:57 +05301152
1153 nlohmann::json &ipv4AddressJson =
1154 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
1155 ipv4AddressJson["Address"] = *address;
1156 ipv4AddressJson["SubnetMask"] = *subnetMask;
1157 ipv4AddressJson["Gateway"] = *gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001158 }
1159 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001160 }
1161 }
1162
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001163 void handleStaticNameServersPatch(
1164 const std::string &ifaceId,
1165 const std::vector<std::string> &updatedStaticNameServers,
1166 const std::shared_ptr<AsyncResp> &asyncResp)
1167 {
1168 crow::connections::systemBus->async_method_call(
1169 [asyncResp,
1170 updatedStaticNameServers](const boost::system::error_code ec) {
1171 if (ec)
1172 {
1173 messages::internalError(asyncResp->res);
1174 return;
1175 }
1176 asyncResp->res.jsonValue["NameServers"] =
1177 updatedStaticNameServers;
1178 asyncResp->res.jsonValue["StaticNameServers"] =
1179 updatedStaticNameServers;
1180 },
1181 "xyz.openbmc_project.Network",
1182 "/xyz/openbmc_project/network/" + ifaceId,
1183 "org.freedesktop.DBus.Properties", "Set",
1184 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1185 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1186 }
1187
Ed Tanous0f74e642018-11-12 15:17:05 -08001188 void parseInterfaceData(
1189 nlohmann::json &json_response, const std::string &iface_id,
1190 const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001191 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001192 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001193 json_response["Id"] = iface_id;
1194 json_response["@odata.id"] =
1195 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001196 json_response["InterfaceEnabled"] = true;
1197 if (ethData.speed == 0)
1198 {
1199 json_response["LinkStatus"] = "NoLink";
1200 json_response["Status"] = {
1201 {"Health", "OK"},
1202 {"State", "Disabled"},
1203 };
1204 }
1205 else
1206 {
1207 json_response["LinkStatus"] = "LinkUp";
1208 json_response["Status"] = {
1209 {"Health", "OK"},
1210 {"State", "Enabled"},
1211 };
1212 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001213 json_response["SpeedMbps"] = ethData.speed;
1214 json_response["MACAddress"] = ethData.mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001215 json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301216
Ed Tanous4a0cb852018-10-15 07:55:04 -07001217 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001218 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001219 json_response["HostName"] = ethData.hostname;
1220 }
1221
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001222 json_response["VLANs"] = {
1223 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1224 iface_id + "/VLANs"}};
1225
Ed Tanous029573d2019-02-01 10:57:49 -08001226 json_response["NameServers"] = ethData.nameservers;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001227 json_response["StaticNameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001228
Ed Tanous4a0cb852018-10-15 07:55:04 -07001229 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001230 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001231 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1232 ipv4_array = nlohmann::json::array();
1233 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001234 {
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001235
1236 std::string gatewayStr = ipv4_config.gateway;
1237 if (gatewayStr.empty())
1238 {
1239 gatewayStr = "0.0.0.0";
1240 }
1241
Ed Tanous029573d2019-02-01 10:57:49 -08001242 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1243 {"SubnetMask", ipv4_config.netmask},
1244 {"Address", ipv4_config.address},
Gunnar Millsfa5053a2019-04-03 16:53:44 -05001245 {"Gateway", gatewayStr}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001246 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001247 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248 }
1249
1250 /**
1251 * Functions triggers appropriate requests on DBus
1252 */
1253 void doGet(crow::Response &res, const crow::Request &req,
1254 const std::vector<std::string> &params) override
1255 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001256 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 if (params.size() != 1)
1258 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001259 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001260 return;
1261 }
1262
Ed Tanous4a0cb852018-10-15 07:55:04 -07001263 getEthernetIfaceData(
1264 params[0],
1265 [this, asyncResp, iface_id{std::string(params[0])}](
1266 const bool &success, const EthernetInterfaceData &ethData,
1267 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1268 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001269 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001270 // TODO(Pawel)consider distinguish between non existing
1271 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001272 messages::resourceNotFound(asyncResp->res,
1273 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001274 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001275 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001276 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001277 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001278 asyncResp->res.jsonValue["@odata.context"] =
1279 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1280 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1281 asyncResp->res.jsonValue["Description"] =
1282 "Management Network Interface";
1283
1284 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1285 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001286 });
manojkiraneda2a133282019-02-19 13:09:43 +05301287 getDHCPConfigData(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001288 }
1289
1290 void doPatch(crow::Response &res, const crow::Request &req,
1291 const std::vector<std::string> &params) override
1292 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001293 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001294 if (params.size() != 1)
1295 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001296 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001297 return;
1298 }
1299
Ed Tanous4a0cb852018-10-15 07:55:04 -07001300 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001301
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001302 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301303 std::optional<std::string> macAddress;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301304 std::optional<nlohmann::json> ipv4Addresses;
1305 std::optional<nlohmann::json> ipv6Addresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001306 std::optional<std::vector<std::string>> staticNameServers;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001307
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001308 if (!json_util::readJson(
1309 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001310 "IPv6Addresses", ipv6Addresses, "MACAddress", macAddress,
1311 "StaticNameServers", staticNameServers))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001312 {
1313 return;
1314 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301315
Ed Tanous4a0cb852018-10-15 07:55:04 -07001316 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001317 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001318 getEthernetIfaceData(
1319 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001320 [this, asyncResp, iface_id, hostname = std::move(hostname),
1321 macAddress = std::move(macAddress),
Ed Tanous0627a2c2018-11-29 17:09:23 -08001322 ipv4Addresses = std::move(ipv4Addresses),
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001323 ipv6Addresses = std::move(ipv6Addresses),
1324 staticNameServers = std::move(staticNameServers)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001325 const bool &success, const EthernetInterfaceData &ethData,
1326 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001327 if (!success)
1328 {
1329 // ... otherwise return error
1330 // TODO(Pawel)consider distinguish between non existing
1331 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001332 messages::resourceNotFound(asyncResp->res,
1333 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001334 return;
1335 }
1336
Ed Tanous0f74e642018-11-12 15:17:05 -08001337 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1338 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001339
Ed Tanous0627a2c2018-11-29 17:09:23 -08001340 if (hostname)
1341 {
1342 handleHostnamePatch(*hostname, asyncResp);
1343 }
1344
Ratan Guptad5776652019-03-03 08:47:22 +05301345 if (macAddress)
1346 {
1347 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1348 }
1349
Ed Tanous0627a2c2018-11-29 17:09:23 -08001350 if (ipv4Addresses)
1351 {
Ed Tanous537174c2018-12-10 15:09:31 -08001352 // TODO(ed) for some reason the capture of ipv4Addresses
1353 // above is returning a const value, not a non-const value.
1354 // This doesn't really work for us, as we need to be able to
1355 // efficiently move out the intermedia nlohmann::json
1356 // objects. This makes a copy of the structure, and operates
1357 // on that, but could be done more efficiently
Ratan Guptaf476acb2019-03-02 16:46:57 +05301358 nlohmann::json ipv4 = std::move(*ipv4Addresses);
Ed Tanous537174c2018-12-10 15:09:31 -08001359 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001360 }
1361
1362 if (ipv6Addresses)
1363 {
1364 // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1365 messages::propertyNotWritable(asyncResp->res,
1366 "IPv6Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001367 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001368
1369 if (staticNameServers)
1370 {
1371 handleStaticNameServersPatch(iface_id, *staticNameServers,
1372 asyncResp);
1373 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001374 });
1375 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001376};
1377
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001378/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001379 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1380 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001381 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001382class VlanNetworkInterface : public Node
1383{
1384 public:
1385 /*
1386 * Default Constructor
1387 */
1388 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001389 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001390 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001391 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001392 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001393 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001394 entityPrivileges = {
1395 {boost::beast::http::verb::get, {{"Login"}}},
1396 {boost::beast::http::verb::head, {{"Login"}}},
1397 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1398 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1399 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1400 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001401 }
1402
Ed Tanous1abe55e2018-09-05 08:30:59 -07001403 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001404 void parseInterfaceData(
1405 nlohmann::json &json_response, const std::string &parent_iface_id,
1406 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001407 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001408 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001410 json_response["Id"] = iface_id;
1411 json_response["@odata.id"] =
1412 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1413 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001414
Ed Tanous4a0cb852018-10-15 07:55:04 -07001415 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001416 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001417 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001418 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07001419 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001420 }
1421
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001422 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001423 {
1424 if (!boost::starts_with(iface, parent + "_"))
1425 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001426 return false;
1427 }
1428 else
1429 {
1430 return true;
1431 }
1432 }
1433
1434 /**
1435 * Functions triggers appropriate requests on DBus
1436 */
1437 void doGet(crow::Response &res, const crow::Request &req,
1438 const std::vector<std::string> &params) override
1439 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001440 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1441 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001442 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1443 // Check if there is required param, truly entering this shall be
1444 // impossible.
1445 if (params.size() != 2)
1446 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001447 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001448 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001449 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001450 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001451
Ed Tanous4a0cb852018-10-15 07:55:04 -07001452 const std::string &parent_iface_id = params[0];
1453 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001454 res.jsonValue["@odata.type"] =
1455 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1456 res.jsonValue["@odata.context"] =
1457 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1458 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001459
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001460 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001461 {
1462 return;
1463 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001464
Ed Tanous1abe55e2018-09-05 08:30:59 -07001465 // Get single eth interface data, and call the below callback for JSON
1466 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001467 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001468 params[1],
1469 [this, asyncResp, parent_iface_id{std::string(params[0])},
1470 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001471 const bool &success, const EthernetInterfaceData &ethData,
1472 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001473 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001474 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001475 parseInterfaceData(asyncResp->res.jsonValue,
1476 parent_iface_id, iface_id, ethData,
1477 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001478 }
1479 else
1480 {
1481 // ... otherwise return error
1482 // TODO(Pawel)consider distinguish between non existing
1483 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001484 messages::resourceNotFound(
1485 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001486 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001487 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001488 }
1489
Ed Tanous1abe55e2018-09-05 08:30:59 -07001490 void doPatch(crow::Response &res, const crow::Request &req,
1491 const std::vector<std::string> &params) override
1492 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001493 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001494 if (params.size() != 2)
1495 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001496 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001497 return;
1498 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001499
Ed Tanous1abe55e2018-09-05 08:30:59 -07001500 const std::string &parentIfaceId = params[0];
1501 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001502
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001503 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001504 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001505 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1506 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001507 return;
1508 }
1509
Ed Tanous0627a2c2018-11-29 17:09:23 -08001510 bool vlanEnable = false;
1511 uint64_t vlanId = 0;
1512
1513 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1514 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001515 {
1516 return;
1517 }
1518
1519 // Get single eth interface data, and call the below callback for JSON
1520 // preparation
Sunitha Harish08244d02019-04-01 03:57:25 -05001521 getEthernetIfaceData(params[1], [this, asyncResp,
1522 parentIfaceId{std::string(params[0])},
1523 ifaceId{std::string(params[1])},
1524 &vlanEnable, &vlanId](
1525 const bool &success,
1526 const EthernetInterfaceData
1527 &ethData,
1528 const boost::container::flat_set<
1529 IPv4AddressData> &ipv4Data) {
1530 if (success && !ethData.vlan_id.empty())
1531 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001532 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1533 ifaceId, ethData, ipv4Data);
Sunitha Harish08244d02019-04-01 03:57:25 -05001534 auto callback =
1535 [asyncResp](const boost::system::error_code ec) {
1536 if (ec)
1537 {
1538 messages::internalError(asyncResp->res);
1539 }
1540 };
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541
Sunitha Harish08244d02019-04-01 03:57:25 -05001542 if (vlanEnable == true)
1543 {
1544 crow::connections::systemBus->async_method_call(
1545 std::move(callback), "xyz.openbmc_project.Network",
1546 "/xyz/openbmc_project/network/" + ifaceId,
1547 "org.freedesktop.DBus.Properties", "Set",
1548 "xyz.openbmc_project.Network.VLAN", "Id",
1549 std::variant<uint32_t>(vlanId));
1550 }
1551 else
1552 {
1553 BMCWEB_LOG_DEBUG
1554 << "vlanEnable is false. Deleting the vlan interface";
1555 crow::connections::systemBus->async_method_call(
1556 std::move(callback), "xyz.openbmc_project.Network",
1557 std::string("/xyz/openbmc_project/network/") + ifaceId,
1558 "xyz.openbmc_project.Object.Delete", "Delete");
1559 }
1560 }
1561 else
1562 {
1563 // TODO(Pawel)consider distinguish between non existing
1564 // object, and other errors
1565 messages::resourceNotFound(asyncResp->res,
1566 "VLAN Network Interface", ifaceId);
1567 return;
1568 }
1569 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001570 }
1571
1572 void doDelete(crow::Response &res, const crow::Request &req,
1573 const std::vector<std::string> &params) override
1574 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001575 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001576 if (params.size() != 2)
1577 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001578 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 return;
1580 }
1581
1582 const std::string &parentIfaceId = params[0];
1583 const std::string &ifaceId = params[1];
1584
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001585 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001586 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001587 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1588 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589 return;
1590 }
1591
1592 // Get single eth interface data, and call the below callback for JSON
1593 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001594 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001595 params[1],
1596 [this, asyncResp, parentIfaceId{std::string(params[0])},
1597 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001598 const bool &success, const EthernetInterfaceData &ethData,
1599 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001600 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07001601 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001602 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1603 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001604
Jason M. Billsf12894f2018-10-09 12:45:45 -07001605 auto callback =
1606 [asyncResp](const boost::system::error_code ec) {
1607 if (ec)
1608 {
1609 messages::internalError(asyncResp->res);
1610 }
1611 };
1612 crow::connections::systemBus->async_method_call(
1613 std::move(callback), "xyz.openbmc_project.Network",
1614 std::string("/xyz/openbmc_project/network/") + ifaceId,
1615 "xyz.openbmc_project.Object.Delete", "Delete");
1616 }
1617 else
1618 {
1619 // ... otherwise return error
1620 // TODO(Pawel)consider distinguish between non existing
1621 // object, and other errors
1622 messages::resourceNotFound(
1623 asyncResp->res, "VLAN Network Interface", ifaceId);
1624 }
1625 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001627};
1628
1629/**
1630 * VlanNetworkInterfaceCollection derived class for delivering
1631 * VLANNetworkInterface Collection Schema
1632 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633class VlanNetworkInterfaceCollection : public Node
1634{
1635 public:
1636 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001638 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1639 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001640 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001641 entityPrivileges = {
1642 {boost::beast::http::verb::get, {{"Login"}}},
1643 {boost::beast::http::verb::head, {{"Login"}}},
1644 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1645 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1646 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1647 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001648 }
1649
Ed Tanous1abe55e2018-09-05 08:30:59 -07001650 private:
1651 /**
1652 * Functions triggers appropriate requests on DBus
1653 */
1654 void doGet(crow::Response &res, const crow::Request &req,
1655 const std::vector<std::string> &params) override
1656 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001657 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001658 if (params.size() != 1)
1659 {
1660 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07001661 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001662 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07001663 }
1664
Ed Tanous4a0cb852018-10-15 07:55:04 -07001665 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001666
Ed Tanous4a0cb852018-10-15 07:55:04 -07001667 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001669 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08001670 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001671 const bool &success,
1672 const std::vector<std::string> &iface_list) {
1673 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001674 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001675 messages::internalError(asyncResp->res);
1676 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001678 asyncResp->res.jsonValue["@odata.type"] =
1679 "#VLanNetworkInterfaceCollection."
1680 "VLanNetworkInterfaceCollection";
1681 asyncResp->res.jsonValue["@odata.context"] =
1682 "/redfish/v1/$metadata"
1683 "#VLanNetworkInterfaceCollection."
1684 "VLanNetworkInterfaceCollection";
1685 asyncResp->res.jsonValue["Name"] =
1686 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07001687
Jason M. Billsf12894f2018-10-09 12:45:45 -07001688 nlohmann::json iface_array = nlohmann::json::array();
1689
1690 for (const std::string &iface_item : iface_list)
1691 {
1692 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
1693 {
1694 iface_array.push_back(
1695 {{"@odata.id",
1696 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1697 rootInterfaceName + "/VLANs/" + iface_item}});
1698 }
1699 }
1700
Jason M. Billsf12894f2018-10-09 12:45:45 -07001701 asyncResp->res.jsonValue["Members@odata.count"] =
1702 iface_array.size();
1703 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
1704 asyncResp->res.jsonValue["@odata.id"] =
1705 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1706 rootInterfaceName + "/VLANs";
1707 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001709
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 void doPost(crow::Response &res, const crow::Request &req,
1711 const std::vector<std::string> &params) override
1712 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001713 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001714 if (params.size() != 1)
1715 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001716 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717 return;
1718 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001719 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001720 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001721 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
1722 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001723 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001724 return;
1725 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001726 // Need both vlanId and vlanEnable to service this request
1727 if (!vlanId)
1728 {
1729 messages::propertyMissing(asyncResp->res, "VLANId");
1730 }
1731 if (!vlanEnable)
1732 {
1733 messages::propertyMissing(asyncResp->res, "VLANEnable");
1734 }
1735 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1736 {
1737 return;
1738 }
1739
Ed Tanous4a0cb852018-10-15 07:55:04 -07001740 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07001741 auto callback = [asyncResp](const boost::system::error_code ec) {
1742 if (ec)
1743 {
1744 // TODO(ed) make more consistent error messages based on
1745 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07001746 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001747 return;
1748 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001749 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001750 };
1751 crow::connections::systemBus->async_method_call(
1752 std::move(callback), "xyz.openbmc_project.Network",
1753 "/xyz/openbmc_project/network",
1754 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08001755 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001756 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001757};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001758} // namespace redfish