blob: e861fb83a3f1dda274d79bbb9cfa944de3be7c49 [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>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace redfish
27{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010028
29/**
30 * DBus types primitives for several generic DBus interfaces
31 * TODO(Pawel) consider move this to separate file into boost::dbus
32 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070033using PropertiesMapType = boost::container::flat_map<
34 std::string,
35 sdbusplus::message::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<
43 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
Ed Tanous4a0cb852018-10-15 07:55:04 -070045 int32_t, uint32_t, int64_t, uint64_t, double>>>>>>;
46
47enum class LinkType
48{
49 Local,
50 Global
51};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010052
53/**
54 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010055 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070056struct IPv4AddressData
57{
58 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070059 std::string address;
60 std::string domain;
61 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 std::string netmask;
63 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070064 LinkType linktype;
65
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 bool operator<(const IPv4AddressData &obj) const
67 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070068 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010070};
71
72/**
73 * Structure for keeping basic single Ethernet Interface information
74 * available from DBus
75 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070076struct EthernetInterfaceData
77{
Ed Tanous4a0cb852018-10-15 07:55:04 -070078 uint32_t speed;
79 bool auto_neg;
80 std::string hostname;
81 std::string default_gateway;
82 std::string mac_address;
Ed Tanousa24526d2018-12-10 15:17:59 -080083 std::optional<uint32_t> vlan_id;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010084};
85
Ed Tanous4a0cb852018-10-15 07:55:04 -070086// Helper function that changes bits netmask notation (i.e. /24)
87// into full dot notation
88inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -070089{
Ed Tanous4a0cb852018-10-15 07:55:04 -070090 uint32_t value = 0xffffffff << (32 - bits);
91 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
92 std::to_string((value >> 16) & 0xff) + "." +
93 std::to_string((value >> 8) & 0xff) + "." +
94 std::to_string(value & 0xff);
95 return netmask;
96}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010097
Ed Tanous4a0cb852018-10-15 07:55:04 -070098inline std::string
99 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
100 bool isIPv4)
101{
102 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700104 return "Static";
105 }
106 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
107 {
108 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700110 return "IPv4LinkLocal";
111 }
112 else
113 {
114 return "LinkLocal";
115 }
116 }
117 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
118 {
119 if (isIPv4)
120 {
121 return "DHCP";
122 }
123 else
124 {
125 return "DHCPv6";
126 }
127 }
128 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
129 {
130 return "SLAAC";
131 }
132 return "";
133}
134
135inline std::string
136 translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
137{
138 if (inputOrigin == "Static")
139 {
140 return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
141 }
142 if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
143 {
144 return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
145 }
146 if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
147 {
148 return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
149 }
150 if (inputOrigin == "SLAAC")
151 {
152 return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
153 }
154 return "";
155}
156
157inline void extractEthernetInterfaceData(const std::string &ethiface_id,
158 const GetManagedObjects &dbus_data,
159 EthernetInterfaceData &ethData)
160{
161 for (const auto &objpath : dbus_data)
162 {
163 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
164 {
165 for (const auto &ifacePair : objpath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 {
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 Tanous1b6b96c2018-11-30 11:35:41 -0800174 sdbusplus::message::variant_ns::get_if<
175 std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700176 if (mac != nullptr)
177 {
178 ethData.mac_address = *mac;
179 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700181 }
182 }
183 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
184 {
185 for (const auto &propertyPair : ifacePair.second)
186 {
187 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800189 const uint32_t *id =
190 sdbusplus::message::variant_ns::get_if<
191 uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700192 if (id != nullptr)
193 {
194 ethData.vlan_id = *id;
195 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700197 }
198 }
199 else if (ifacePair.first ==
200 "xyz.openbmc_project.Network.EthernetInterface")
201 {
202 for (const auto &propertyPair : ifacePair.second)
203 {
204 if (propertyPair.first == "AutoNeg")
205 {
206 const bool *auto_neg =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800207 sdbusplus::message::variant_ns::get_if<bool>(
208 &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 Tanous1b6b96c2018-11-30 11:35:41 -0800217 sdbusplus::message::variant_ns::get_if<
218 uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700219 if (speed != nullptr)
220 {
221 ethData.speed = *speed;
222 }
223 }
224 }
225 }
226 else if (ifacePair.first ==
227 "xyz.openbmc_project.Network.SystemConfiguration")
228 {
229 for (const auto &propertyPair : ifacePair.second)
230 {
231 if (propertyPair.first == "HostName")
232 {
233 const std::string *hostname =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800234 sdbusplus::message::variant_ns::get_if<
235 std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700236 if (hostname != nullptr)
237 {
238 ethData.hostname = *hostname;
239 }
240 }
241 else if (propertyPair.first == "DefaultGateway")
242 {
243 const std::string *defaultGateway =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800244 sdbusplus::message::variant_ns::get_if<
245 std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700246 if (defaultGateway != nullptr)
247 {
248 ethData.default_gateway = *defaultGateway;
249 }
250 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 }
252 }
253 }
254 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700256}
257
258// Helper function that extracts data for single ethernet ipv4 address
259inline void
260 extractIPData(const std::string &ethiface_id,
261 const GetManagedObjects &dbus_data,
262 boost::container::flat_set<IPv4AddressData> &ipv4_config)
263{
264 const std::string ipv4PathStart =
265 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
266
267 // Since there might be several IPv4 configurations aligned with
268 // single ethernet interface, loop over all of them
269 for (const auto &objpath : dbus_data)
270 {
271 // Check if proper pattern for object path appears
272 if (boost::starts_with(objpath.first.str, ipv4PathStart))
273 {
274 for (auto &interface : objpath.second)
275 {
276 if (interface.first == "xyz.openbmc_project.Network.IP")
277 {
278 // Instance IPv4AddressData structure, and set as
279 // appropriate
280 std::pair<
281 boost::container::flat_set<IPv4AddressData>::iterator,
282 bool>
283 it = ipv4_config.insert(
284 {objpath.first.str.substr(ipv4PathStart.size())});
285 IPv4AddressData &ipv4_address = *it.first;
286 for (auto &property : interface.second)
287 {
288 if (property.first == "Address")
289 {
290 const std::string *address =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800291 sdbusplus::message::variant_ns::get_if<
292 std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700293 if (address != nullptr)
294 {
295 ipv4_address.address = *address;
296 }
297 }
298 else if (property.first == "Gateway")
299 {
300 const std::string *gateway =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800301 sdbusplus::message::variant_ns::get_if<
302 std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700303 if (gateway != nullptr)
304 {
305 ipv4_address.gateway = *gateway;
306 }
307 }
308 else if (property.first == "Origin")
309 {
310 const std::string *origin =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800311 sdbusplus::message::variant_ns::get_if<
312 std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700313 if (origin != nullptr)
314 {
315 ipv4_address.origin =
316 translateAddressOriginDbusToRedfish(*origin,
317 true);
318 }
319 }
320 else if (property.first == "PrefixLength")
321 {
322 const uint8_t *mask =
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800323 sdbusplus::message::variant_ns::get_if<uint8_t>(
324 &property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700325 if (mask != nullptr)
326 {
327 // convert it to the string
328 ipv4_address.netmask = getNetmask(*mask);
329 }
330 }
331 else
332 {
333 BMCWEB_LOG_ERROR
334 << "Got extra property: " << property.first
335 << " on the " << objpath.first.str << " object";
336 }
337 }
338 // Check if given address is local, or global
339 ipv4_address.linktype =
340 boost::starts_with(ipv4_address.address, "169.254.")
341 ? LinkType::Global
342 : LinkType::Local;
343 }
344 }
345 }
346 }
347}
348
349/**
350 * @brief Sets given Id on the given VLAN interface through D-Bus
351 *
352 * @param[in] ifaceId Id of VLAN interface that should be modified
353 * @param[in] inputVlanId New ID of the VLAN
354 * @param[in] callback Function that will be called after the operation
355 *
356 * @return None.
357 */
358template <typename CallbackFunc>
359void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
360 CallbackFunc &&callback)
361{
362 crow::connections::systemBus->async_method_call(
363 callback, "xyz.openbmc_project.Network",
364 std::string("/xyz/openbmc_project/network/") + ifaceId,
365 "org.freedesktop.DBus.Properties", "Set",
366 "xyz.openbmc_project.Network.VLAN", "Id",
367 sdbusplus::message::variant<uint32_t>(inputVlanId));
368}
369
370/**
371 * @brief Helper function that verifies IP address to check if it is in
372 * proper format. If bits pointer is provided, also calculates active
373 * bit count for Subnet Mask.
374 *
375 * @param[in] ip IP that will be verified
376 * @param[out] bits Calculated mask in bits notation
377 *
378 * @return true in case of success, false otherwise
379 */
380inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
381 uint8_t *bits = nullptr)
382{
383 std::vector<std::string> bytesInMask;
384
385 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700386
387 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700388 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700390 return false;
391 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392
Ed Tanous4a0cb852018-10-15 07:55:04 -0700393 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700394 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700395 *bits = 0;
396 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397
Ed Tanous4a0cb852018-10-15 07:55:04 -0700398 char *endPtr;
399 long previousValue = 255;
400 bool firstZeroInByteHit;
401 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700403 if (byte.empty())
404 {
405 return false;
406 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407
Ed Tanous4a0cb852018-10-15 07:55:04 -0700408 // Use strtol instead of stroi to avoid exceptions
409 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410
Ed Tanous4a0cb852018-10-15 07:55:04 -0700411 // endPtr should point to the end of the string, otherwise given string
412 // is not 100% number
413 if (*endPtr != '\0')
414 {
415 return false;
416 }
417
418 // Value should be contained in byte
419 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 {
421 return false;
422 }
423
424 if (bits != nullptr)
425 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700426 // Mask has to be continuous between bytes
427 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700428 {
429 return false;
430 }
431
Ed Tanous4a0cb852018-10-15 07:55:04 -0700432 // Mask has to be continuous inside bytes
433 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434
Ed Tanous4a0cb852018-10-15 07:55:04 -0700435 // Count bits
436 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700438 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700440 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700442 // Continuity not preserved
443 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444 }
445 else
446 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700447 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 }
449 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 else
451 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700452 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700454 }
455 }
456
457 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458 }
459
Ed Tanous4a0cb852018-10-15 07:55:04 -0700460 return true;
461}
462
463/**
464 * @brief Changes IPv4 address type property (Address, Gateway)
465 *
466 * @param[in] ifaceId Id of interface whose IP should be modified
467 * @param[in] ipIdx Index of IP in input array that should be modified
468 * @param[in] ipHash DBus Hash id of modified IP
469 * @param[in] name Name of field in JSON representation
470 * @param[in] newValue New value that should be written
471 * @param[io] asyncResp Response object that will be returned to client
472 *
473 * @return true if give IP is valid and has been sent do D-Bus, false
474 * otherwise
475 */
476inline void changeIPv4AddressProperty(
477 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
478 const std::string &name, const std::string &newValue,
479 const std::shared_ptr<AsyncResp> asyncResp)
480{
481 auto callback = [asyncResp, ipIdx, name{std::string(name)},
482 newValue{std::move(newValue)}](
483 const boost::system::error_code ec) {
484 if (ec)
485 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800486 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700487 }
488 else
489 {
490 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
491 }
492 };
493
494 crow::connections::systemBus->async_method_call(
495 std::move(callback), "xyz.openbmc_project.Network",
496 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
497 "org.freedesktop.DBus.Properties", "Set",
498 "xyz.openbmc_project.Network.IP", name,
499 sdbusplus::message::variant<std::string>(newValue));
500}
501
502/**
503 * @brief Changes IPv4 address origin property
504 *
505 * @param[in] ifaceId Id of interface whose IP should be modified
506 * @param[in] ipIdx Index of IP in input array that should be
507 * modified
508 * @param[in] ipHash DBus Hash id of modified IP
509 * @param[in] newValue New value in Redfish format
510 * @param[in] newValueDbus New value in D-Bus format
511 * @param[io] asyncResp Response object that will be returned to client
512 *
513 * @return true if give IP is valid and has been sent do D-Bus, false
514 * otherwise
515 */
516inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
517 const std::string &ipHash,
518 const std::string &newValue,
519 const std::string &newValueDbus,
520 const std::shared_ptr<AsyncResp> asyncResp)
521{
522 auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
523 const boost::system::error_code ec) {
524 if (ec)
525 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800526 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700527 }
528 else
529 {
530 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
531 newValue;
532 }
533 };
534
535 crow::connections::systemBus->async_method_call(
536 std::move(callback), "xyz.openbmc_project.Network",
537 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
538 "org.freedesktop.DBus.Properties", "Set",
539 "xyz.openbmc_project.Network.IP", "Origin",
540 sdbusplus::message::variant<std::string>(newValueDbus));
541}
542
543/**
544 * @brief Modifies SubnetMask for given IP
545 *
546 * @param[in] ifaceId Id of interface whose IP should be modified
547 * @param[in] ipIdx Index of IP in input array that should be
548 * modified
549 * @param[in] ipHash DBus Hash id of modified IP
550 * @param[in] newValueStr Mask in dot notation as string
551 * @param[in] newValue Mask as PrefixLength in bitcount
552 * @param[io] asyncResp Response object that will be returned to client
553 *
554 * @return None
555 */
556inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
557 const std::string &ipHash,
558 const std::string &newValueStr,
559 uint8_t &newValue,
560 std::shared_ptr<AsyncResp> asyncResp)
561{
562 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
563 const boost::system::error_code ec) {
564 if (ec)
565 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800566 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700567 }
568 else
569 {
570 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
571 newValueStr;
572 }
573 };
574
575 crow::connections::systemBus->async_method_call(
576 std::move(callback), "xyz.openbmc_project.Network",
577 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
578 "org.freedesktop.DBus.Properties", "Set",
579 "xyz.openbmc_project.Network.IP", "PrefixLength",
580 sdbusplus::message::variant<uint8_t>(newValue));
581}
582
583/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700584 * @brief Deletes given IPv4
585 *
586 * @param[in] ifaceId Id of interface whose IP should be deleted
587 * @param[in] ipIdx Index of IP in input array that should be deleted
588 * @param[in] ipHash DBus Hash id of IP that should be deleted
589 * @param[io] asyncResp Response object that will be returned to client
590 *
591 * @return None
592 */
593inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
594 unsigned int ipIdx,
595 const std::shared_ptr<AsyncResp> asyncResp)
596{
597 crow::connections::systemBus->async_method_call(
598 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 if (ec)
600 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800601 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100602 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700603 else
604 {
605 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
606 }
607 },
608 "xyz.openbmc_project.Network",
609 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
610 "xyz.openbmc_project.Object.Delete", "Delete");
611}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612
Ed Tanous4a0cb852018-10-15 07:55:04 -0700613/**
614 * @brief Creates IPv4 with given data
615 *
616 * @param[in] ifaceId Id of interface whose IP should be deleted
617 * @param[in] ipIdx Index of IP in input array that should be deleted
618 * @param[in] ipHash DBus Hash id of IP that should be deleted
619 * @param[io] asyncResp Response object that will be returned to client
620 *
621 * @return None
622 */
623inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
624 uint8_t subnetMask, const std::string &gateway,
625 const std::string &address,
626 std::shared_ptr<AsyncResp> asyncResp)
627{
628 auto createIpHandler = [ipIdx,
629 asyncResp](const boost::system::error_code ec) {
630 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800632 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 };
635
Ed Tanous4a0cb852018-10-15 07:55:04 -0700636 crow::connections::systemBus->async_method_call(
637 std::move(createIpHandler), "xyz.openbmc_project.Network",
638 "/xyz/openbmc_project/network/" + ifaceId,
639 "xyz.openbmc_project.Network.IP.Create", "IP",
640 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
641 gateway);
642}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643
Ed Tanous4a0cb852018-10-15 07:55:04 -0700644/**
645 * Function that retrieves all properties for given Ethernet Interface
646 * Object
647 * from EntityManager Network Manager
648 * @param ethiface_id a eth interface id to query on DBus
649 * @param callback a function that shall be called to convert Dbus output
650 * into JSON
651 */
652template <typename CallbackFunc>
653void getEthernetIfaceData(const std::string &ethiface_id,
654 CallbackFunc &&callback)
655{
656 crow::connections::systemBus->async_method_call(
657 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
658 const boost::system::error_code error_code,
659 const GetManagedObjects &resp) {
660 EthernetInterfaceData ethData{};
661 boost::container::flat_set<IPv4AddressData> ipv4Data;
662
663 if (error_code)
664 {
665 callback(false, ethData, ipv4Data);
666 return;
667 }
668
669 extractEthernetInterfaceData(ethiface_id, resp, ethData);
670 extractIPData(ethiface_id, resp, ipv4Data);
671
672 // Fix global GW
673 for (IPv4AddressData &ipv4 : ipv4Data)
674 {
675 if ((ipv4.linktype == LinkType::Global) &&
676 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700678 ipv4.gateway = ethData.default_gateway;
679 }
680 }
681
682 // Finally make a callback with usefull data
683 callback(true, ethData, ipv4Data);
684 },
685 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
686 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
687};
688
689/**
690 * Function that retrieves all Ethernet Interfaces available through Network
691 * Manager
692 * @param callback a function that shall be called to convert Dbus output
693 * into JSON.
694 */
695template <typename CallbackFunc>
696void getEthernetIfaceList(CallbackFunc &&callback)
697{
698 crow::connections::systemBus->async_method_call(
699 [callback{std::move(callback)}](
700 const boost::system::error_code error_code,
701 GetManagedObjects &resp) {
702 // Callback requires vector<string> to retrieve all available
703 // ethernet interfaces
704 std::vector<std::string> iface_list;
705 iface_list.reserve(resp.size());
706 if (error_code)
707 {
708 callback(false, iface_list);
709 return;
710 }
711
712 // Iterate over all retrieved ObjectPaths.
713 for (const auto &objpath : resp)
714 {
715 // And all interfaces available for certain ObjectPath.
716 for (const auto &interface : objpath.second)
717 {
718 // If interface is
719 // xyz.openbmc_project.Network.EthernetInterface, this is
720 // what we're looking for.
721 if (interface.first ==
722 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700724 // Cut out everyting until last "/", ...
725 const std::string &iface_id = objpath.first.str;
726 std::size_t last_pos = iface_id.rfind("/");
727 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700729 // and put it into output vector.
730 iface_list.emplace_back(
731 iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 }
733 }
734 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700735 }
736 // Finally make a callback with useful data
737 callback(true, iface_list);
738 },
739 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
740 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100741};
742
743/**
744 * EthernetCollection derived class for delivering Ethernet Collection Schema
745 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746class EthernetCollection : public Node
747{
748 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700749 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700751 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 entityPrivileges = {
754 {boost::beast::http::verb::get, {{"Login"}}},
755 {boost::beast::http::verb::head, {{"Login"}}},
756 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
757 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
758 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
759 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
760 }
761
762 private:
763 /**
764 * Functions triggers appropriate requests on DBus
765 */
766 void doGet(crow::Response &res, const crow::Request &req,
767 const std::vector<std::string> &params) override
768 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800769 res.jsonValue["@odata.type"] =
770 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
771 res.jsonValue["@odata.context"] =
772 "/redfish/v1/"
773 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
774 res.jsonValue["@odata.id"] =
775 "/redfish/v1/Managers/bmc/EthernetInterfaces";
776 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
777 res.jsonValue["Description"] =
778 "Collection of EthernetInterfaces for this Manager";
779
Ed Tanous4a0cb852018-10-15 07:55:04 -0700780 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700782 getEthernetIfaceList(
783 [&res](const bool &success,
784 const std::vector<std::string> &iface_list) {
785 if (!success)
786 {
787 messages::internalError(res);
788 res.end();
789 return;
790 }
791
792 nlohmann::json &iface_array = res.jsonValue["Members"];
793 iface_array = nlohmann::json::array();
794 for (const std::string &iface_item : iface_list)
795 {
796 iface_array.push_back(
797 {{"@odata.id",
798 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
799 iface_item}});
800 }
801
802 res.jsonValue["Members@odata.count"] = iface_array.size();
803 res.jsonValue["@odata.id"] =
804 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 res.end();
Jason M. Billsf12894f2018-10-09 12:45:45 -0700806 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700807 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100808};
809
810/**
811 * EthernetInterface derived class for delivering Ethernet Schema
812 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813class EthernetInterface : public Node
814{
815 public:
816 /*
817 * Default Constructor
818 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700819 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700821 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 std::string())
823 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 entityPrivileges = {
825 {boost::beast::http::verb::get, {{"Login"}}},
826 {boost::beast::http::verb::head, {{"Login"}}},
827 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
828 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
829 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
830 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200831 }
832
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 // TODO(kkowalsk) Find a suitable class/namespace for this
Ed Tanous0627a2c2018-11-29 17:09:23 -0800834 static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable,
835 uint64_t vlanId,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700836 const EthernetInterfaceData &ethData,
837 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700839 if (!ethData.vlan_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 {
841 // This interface is not a VLAN. Cannot do anything with it
842 // TODO(kkowalsk) Change this message
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800843 messages::propertyNotWritable(asyncResp->res, "VLANEnable");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 return;
846 }
847
848 // VLAN is configured on the interface
Ed Tanous0627a2c2018-11-29 17:09:23 -0800849 if (vlanEnable == true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
851 // Change VLAN Id
Ed Tanous0627a2c2018-11-29 17:09:23 -0800852 asyncResp->res.jsonValue["VLANId"] = vlanId;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700853 auto callback = [asyncResp](const boost::system::error_code ec) {
854 if (ec)
855 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700856 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700857 }
858 else
859 {
860 asyncResp->res.jsonValue["VLANEnable"] = true;
861 }
862 };
863 crow::connections::systemBus->async_method_call(
864 std::move(callback), "xyz.openbmc_project.Network",
865 "/xyz/openbmc_project/network/" + ifaceId,
866 "org.freedesktop.DBus.Properties", "Set",
867 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanous0627a2c2018-11-29 17:09:23 -0800868 sdbusplus::message::variant<uint32_t>(vlanId));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700870 else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700872 auto callback = [asyncResp](const boost::system::error_code ec) {
873 if (ec)
874 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700875 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700876 return;
877 }
878 asyncResp->res.jsonValue["VLANEnable"] = false;
879 };
880
881 crow::connections::systemBus->async_method_call(
882 std::move(callback), "xyz.openbmc_project.Network",
883 "/xyz/openbmc_project/network/" + ifaceId,
884 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700885 }
886 }
887
888 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800889 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700890 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800892 asyncResp->res.jsonValue["HostName"] = hostname;
893 crow::connections::systemBus->async_method_call(
894 [asyncResp](const boost::system::error_code ec) {
895 if (ec)
896 {
897 messages::internalError(asyncResp->res);
898 }
899 },
900 "xyz.openbmc_project.Network",
901 "/xyz/openbmc_project/network/config",
902 "org.freedesktop.DBus.Properties", "Set",
903 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
904 sdbusplus::message::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 }
906
Ed Tanous4a0cb852018-10-15 07:55:04 -0700907 void handleIPv4Patch(
908 const std::string &ifaceId, const nlohmann::json &input,
909 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
910 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 {
912 if (!input.is_array())
913 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700914 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800915 "IPv4Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 return;
917 }
918
919 // According to Redfish PATCH definition, size must be at least equal
Ed Tanous4a0cb852018-10-15 07:55:04 -0700920 if (input.size() < ipv4Data.size())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800922 messages::propertyValueFormatError(asyncResp->res, input.dump(),
923 "IPv4Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 return;
925 }
926
Ed Tanous4a0cb852018-10-15 07:55:04 -0700927 int entryIdx = 0;
928 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
929 ipv4Data.begin();
930 for (const nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700932 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800933 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 // Check that entry is not of some unexpected type
Ed Tanous4a0cb852018-10-15 07:55:04 -0700935 if (!thisJson.is_object() && !thisJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800937 messages::propertyValueTypeError(asyncResp->res,
938 thisJson.dump(),
939 pathString + "/IPv4Address");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940
941 continue;
942 }
943
Ed Tanous4a0cb852018-10-15 07:55:04 -0700944 nlohmann::json::const_iterator addressFieldIt =
945 thisJson.find("Address");
946 const std::string *addressField = nullptr;
947 if (addressFieldIt != thisJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700949 addressField = addressFieldIt->get_ptr<const std::string *>();
950 if (addressField == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700951 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800952 messages::propertyValueFormatError(asyncResp->res,
953 addressFieldIt->dump(),
954 pathString + "/Address");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700955 continue;
956 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700957 else
958 {
959 if (!ipv4VerifyIpAndGetBitcount(*addressField))
960 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700961 messages::propertyValueFormatError(
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800962 asyncResp->res, *addressField,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700963 pathString + "/Address");
964 continue;
965 }
966 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700968
Ed Tanousa24526d2018-12-10 15:17:59 -0800969 std::optional<uint8_t> prefixLength;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700970 const std::string *subnetField = nullptr;
971 nlohmann::json::const_iterator subnetFieldIt =
972 thisJson.find("SubnetMask");
973 if (subnetFieldIt != thisJson.end())
974 {
975 subnetField = subnetFieldIt->get_ptr<const std::string *>();
976 if (subnetField == nullptr)
977 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700978 messages::propertyValueFormatError(
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800979 asyncResp->res, *subnetField,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700980 pathString + "/SubnetMask");
981 continue;
982 }
983 else
984 {
985 prefixLength = 0;
986 if (!ipv4VerifyIpAndGetBitcount(*subnetField,
987 &*prefixLength))
988 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700989 messages::propertyValueFormatError(
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800990 asyncResp->res, *subnetField,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700991 pathString + "/SubnetMask");
992 continue;
993 }
994 }
995 }
996
997 std::string addressOriginInDBusFormat;
998 const std::string *addressOriginField = nullptr;
999 nlohmann::json::const_iterator addressOriginFieldIt =
1000 thisJson.find("AddressOrigin");
1001 if (addressOriginFieldIt != thisJson.end())
1002 {
1003 const std::string *addressOriginField =
1004 addressOriginFieldIt->get_ptr<const std::string *>();
1005 if (addressOriginField == nullptr)
1006 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001007 messages::propertyValueFormatError(
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001008 asyncResp->res, *addressOriginField,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001009 pathString + "/AddressOrigin");
1010 continue;
1011 }
1012 else
1013 {
1014 // Get Address origin in proper format
1015 addressOriginInDBusFormat =
1016 translateAddressOriginRedfishToDbus(
1017 *addressOriginField);
1018 if (addressOriginInDBusFormat.empty())
1019 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001020 messages::propertyValueNotInList(
1021 asyncResp->res, *addressOriginField,
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001022 pathString + "/AddressOrigin");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001023 continue;
1024 }
1025 }
1026 }
1027
1028 nlohmann::json::const_iterator gatewayFieldIt =
1029 thisJson.find("Gateway");
1030 const std::string *gatewayField = nullptr;
1031 if (gatewayFieldIt != thisJson.end())
1032 {
1033 const std::string *gatewayField =
1034 gatewayFieldIt->get_ptr<const std::string *>();
1035 if (gatewayField == nullptr ||
1036 !ipv4VerifyIpAndGetBitcount(*gatewayField))
1037 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001038 messages::propertyValueFormatError(
1039 asyncResp->res, *gatewayField, pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001040 continue;
1041 }
1042 }
1043
1044 // if a vlan already exists, modify the existing
1045 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001046 {
1047 // Existing object that should be modified/deleted/remain
1048 // unchanged
Ed Tanous4a0cb852018-10-15 07:55:04 -07001049 if (thisJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001050 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001051 auto callback = [entryIdx{std::to_string(entryIdx)},
1052 asyncResp](
1053 const boost::system::error_code ec) {
1054 if (ec)
1055 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001056 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001057 return;
1058 }
1059 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
1060 nullptr;
1061 };
1062 crow::connections::systemBus->async_method_call(
1063 std::move(callback), "xyz.openbmc_project.Network",
1064 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1065 thisData->id,
1066 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001068 else if (thisJson.is_object())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001069 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001070 // Apply changes
Ed Tanous4a0cb852018-10-15 07:55:04 -07001071 if (addressField != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001072 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001073 auto callback =
1074 [asyncResp, entryIdx,
1075 addressField{std::string(*addressField)}](
1076 const boost::system::error_code ec) {
1077 if (ec)
1078 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001079 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001080 return;
1081 }
1082 asyncResp->res
1083 .jsonValue["IPv4Addresses"][std::to_string(
1084 entryIdx)]["Address"] = addressField;
1085 };
1086
1087 crow::connections::systemBus->async_method_call(
1088 std::move(callback), "xyz.openbmc_project.Network",
1089 "/xyz/openbmc_project/network/" + ifaceId +
1090 "/ipv4/" + thisData->id,
1091 "org.freedesktop.DBus.Properties", "Set",
1092 "xyz.openbmc_project.Network.IP", "Address",
1093 sdbusplus::message::variant<std::string>(
1094 *addressField));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095 }
1096
Ed Tanous4a0cb852018-10-15 07:55:04 -07001097 if (prefixLength && subnetField != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001098 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001099 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1100 thisData->id, *subnetField,
1101 *prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001102 }
1103
Ed Tanous4a0cb852018-10-15 07:55:04 -07001104 if (!addressOriginInDBusFormat.empty() &&
1105 addressOriginField != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001106 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001107 changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1108 *addressOriginField,
1109 addressOriginInDBusFormat, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001110 }
1111
Ed Tanous4a0cb852018-10-15 07:55:04 -07001112 if (gatewayField != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001113 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001114 auto callback =
1115 [asyncResp, entryIdx,
1116 gatewayField{std::string(*gatewayField)}](
1117 const boost::system::error_code ec) {
1118 if (ec)
1119 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001120 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001121 return;
1122 }
1123 asyncResp->res
1124 .jsonValue["IPv4Addresses"][std::to_string(
1125 entryIdx)]["Gateway"] =
1126 std::move(gatewayField);
1127 };
1128
1129 crow::connections::systemBus->async_method_call(
1130 std::move(callback), "xyz.openbmc_project.Network",
1131 "/xyz/openbmc_project/network/" + ifaceId +
1132 "/ipv4/" + thisData->id,
1133 "org.freedesktop.DBus.Properties", "Set",
1134 "xyz.openbmc_project.Network.IP", "Gateway",
1135 sdbusplus::message::variant<std::string>(
1136 *gatewayField));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001137 }
1138 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001139 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001140 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001141 else
1142 {
1143 // Create IPv4 with provided data
1144 if (gatewayField == nullptr)
1145 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001146 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001147 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001148 continue;
1149 }
1150
1151 if (addressField == nullptr)
1152 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001153 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001154 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001155 continue;
1156 }
1157
1158 if (!prefixLength)
1159 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001160 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001161 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001162 continue;
1163 }
1164
1165 createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField,
1166 *addressField, asyncResp);
1167 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
1168 }
1169 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001170 }
1171 }
1172
Ed Tanous0f74e642018-11-12 15:17:05 -08001173 void parseInterfaceData(
1174 nlohmann::json &json_response, const std::string &iface_id,
1175 const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001176 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001177 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001178 json_response["Id"] = iface_id;
1179 json_response["@odata.id"] =
1180 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001181
Ed Tanous4a0cb852018-10-15 07:55:04 -07001182 json_response["SpeedMbps"] = ethData.speed;
1183 json_response["MACAddress"] = ethData.mac_address;
1184 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001185 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001186 json_response["HostName"] = ethData.hostname;
1187 }
1188
1189 nlohmann::json &vlanObj = json_response["VLAN"];
1190 if (ethData.vlan_id)
1191 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001192 vlanObj["VLANEnable"] = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001193 vlanObj["VLANId"] = *ethData.vlan_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001194 }
1195 else
1196 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001197 vlanObj["VLANEnable"] = false;
1198 vlanObj["VLANId"] = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001199 }
1200
Ed Tanous4a0cb852018-10-15 07:55:04 -07001201 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001202 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001203 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1204 ipv4_array = nlohmann::json::array();
1205 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001206 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001207 if (!ipv4_config.address.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001209 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1210 {"SubnetMask", ipv4_config.netmask},
1211 {"Address", ipv4_config.address}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001212
Ed Tanous4a0cb852018-10-15 07:55:04 -07001213 if (!ipv4_config.gateway.empty())
1214 {
1215 ipv4_array.back()["Gateway"] = ipv4_config.gateway;
1216 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001217 }
1218 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001219 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001220 }
1221
1222 /**
1223 * Functions triggers appropriate requests on DBus
1224 */
1225 void doGet(crow::Response &res, const crow::Request &req,
1226 const std::vector<std::string> &params) override
1227 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001228 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001229 if (params.size() != 1)
1230 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001231 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001232 return;
1233 }
1234
Ed Tanous4a0cb852018-10-15 07:55:04 -07001235 getEthernetIfaceData(
1236 params[0],
1237 [this, asyncResp, iface_id{std::string(params[0])}](
1238 const bool &success, const EthernetInterfaceData &ethData,
1239 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1240 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001241 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001242 // TODO(Pawel)consider distinguish between non existing
1243 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001244 messages::resourceNotFound(asyncResp->res,
1245 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001246 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001247 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001248 asyncResp->res.jsonValue["@odata.type"] =
1249 "#EthernetInterface.v1_2_0.EthernetInterface";
1250 asyncResp->res.jsonValue["@odata.context"] =
1251 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1252 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1253 asyncResp->res.jsonValue["Description"] =
1254 "Management Network Interface";
1255
1256 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1257 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001258 });
1259 }
1260
1261 void doPatch(crow::Response &res, const crow::Request &req,
1262 const std::vector<std::string> &params) override
1263 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001264 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001265 if (params.size() != 1)
1266 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001267 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001268 return;
1269 }
1270
Ed Tanous4a0cb852018-10-15 07:55:04 -07001271 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001272
Ed Tanous0627a2c2018-11-29 17:09:23 -08001273 std::optional<nlohmann::json> vlan;
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001274 std::optional<std::string> hostname;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001275 std::optional<nlohmann::json> ipv4Addresses;
1276 std::optional<nlohmann::json> ipv6Addresses;
1277
1278 if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
1279 "IPv4Addresses", ipv4Addresses,
1280 "IPv6Addresses", ipv6Addresses))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001281 {
1282 return;
1283 }
Ed Tanous0627a2c2018-11-29 17:09:23 -08001284 std::optional<uint64_t> vlanId = 0;
1285 std::optional<bool> vlanEnable = false;
1286 if (vlan)
1287 {
1288 if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable,
1289 "VLANId", vlanId))
1290 {
1291 return;
1292 }
1293 // Need both vlanId and vlanEnable to service this request
1294 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1295 {
1296 if (vlanId)
1297 {
1298 messages::propertyMissing(asyncResp->res, "VLANEnable");
1299 }
1300 else
1301 {
1302 messages::propertyMissing(asyncResp->res, "VLANId");
1303 }
1304
1305 return;
1306 }
1307 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001308
Ed Tanous4a0cb852018-10-15 07:55:04 -07001309 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001310 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001311 getEthernetIfaceData(
1312 iface_id,
Ed Tanous0627a2c2018-11-29 17:09:23 -08001313 [this, asyncResp, iface_id, vlanId, vlanEnable,
1314 hostname = std::move(hostname),
1315 ipv4Addresses = std::move(ipv4Addresses),
1316 ipv6Addresses = std::move(ipv6Addresses)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001317 const bool &success, const EthernetInterfaceData &ethData,
1318 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001319 if (!success)
1320 {
1321 // ... otherwise return error
1322 // TODO(Pawel)consider distinguish between non existing
1323 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001324 messages::resourceNotFound(
1325 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001326 return;
1327 }
1328
Ed Tanous0f74e642018-11-12 15:17:05 -08001329 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1330 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001331
Ed Tanous0627a2c2018-11-29 17:09:23 -08001332 if (vlanId && vlanEnable)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 {
Ed Tanous0627a2c2018-11-29 17:09:23 -08001334 handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData,
1335 asyncResp);
1336 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001337
Ed Tanous0627a2c2018-11-29 17:09:23 -08001338 if (hostname)
1339 {
1340 handleHostnamePatch(*hostname, asyncResp);
1341 }
1342
1343 if (ipv4Addresses)
1344 {
1345 handleIPv4Patch(iface_id, *ipv4Addresses, ipv4Data,
1346 asyncResp);
1347 }
1348
1349 if (ipv6Addresses)
1350 {
1351 // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1352 messages::propertyNotWritable(asyncResp->res,
1353 "IPv6Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001354 }
1355 });
1356 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001357};
1358
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001359/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001360 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1361 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001362 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001363class VlanNetworkInterface : public Node
1364{
1365 public:
1366 /*
1367 * Default Constructor
1368 */
1369 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001370 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001371 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001372 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001373 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001374 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001375 entityPrivileges = {
1376 {boost::beast::http::verb::get, {{"Login"}}},
1377 {boost::beast::http::verb::head, {{"Login"}}},
1378 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1379 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1380 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1381 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001382 }
1383
Ed Tanous1abe55e2018-09-05 08:30:59 -07001384 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001385 void parseInterfaceData(
1386 nlohmann::json &json_response, const std::string &parent_iface_id,
1387 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001388 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001389 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001390 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001391 json_response["Id"] = iface_id;
1392 json_response["@odata.id"] =
1393 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1394 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001395
Ed Tanous4a0cb852018-10-15 07:55:04 -07001396 json_response["VLANEnable"] = true;
1397 if (ethData.vlan_id)
1398 {
1399 json_response["VLANId"] = *ethData.vlan_id;
1400 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001401 }
1402
Ed Tanous1abe55e2018-09-05 08:30:59 -07001403 bool verifyNames(crow::Response &res, const std::string &parent,
1404 const std::string &iface)
1405 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001406 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001407 if (!boost::starts_with(iface, parent + "_"))
1408 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001409 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1410 iface);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001411 return false;
1412 }
1413 else
1414 {
1415 return true;
1416 }
1417 }
1418
1419 /**
1420 * Functions triggers appropriate requests on DBus
1421 */
1422 void doGet(crow::Response &res, const crow::Request &req,
1423 const std::vector<std::string> &params) override
1424 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001425 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1426 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001427 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1428 // Check if there is required param, truly entering this shall be
1429 // impossible.
1430 if (params.size() != 2)
1431 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001432 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001433 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001434 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001435 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001436
Ed Tanous4a0cb852018-10-15 07:55:04 -07001437 const std::string &parent_iface_id = params[0];
1438 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001439 res.jsonValue["@odata.type"] =
1440 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1441 res.jsonValue["@odata.context"] =
1442 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1443 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001444
Ed Tanous4a0cb852018-10-15 07:55:04 -07001445 if (!verifyNames(res, parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001446 {
1447 return;
1448 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001449
Ed Tanous1abe55e2018-09-05 08:30:59 -07001450 // Get single eth interface data, and call the below callback for JSON
1451 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001452 getEthernetIfaceData(
1453 iface_id,
1454 [this, asyncResp, parent_iface_id, iface_id](
1455 const bool &success, const EthernetInterfaceData &ethData,
1456 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1457 if (success && ethData.vlan_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001458 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001459 parseInterfaceData(asyncResp->res.jsonValue,
1460 parent_iface_id, iface_id, ethData,
1461 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001462 }
1463 else
1464 {
1465 // ... otherwise return error
1466 // TODO(Pawel)consider distinguish between non existing
1467 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001468 messages::resourceNotFound(
1469 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001470 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001471 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001472 }
1473
Ed Tanous1abe55e2018-09-05 08:30:59 -07001474 void doPatch(crow::Response &res, const crow::Request &req,
1475 const std::vector<std::string> &params) override
1476 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001477 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001478 if (params.size() != 2)
1479 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001480 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001481 return;
1482 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001483
Ed Tanous1abe55e2018-09-05 08:30:59 -07001484 const std::string &parentIfaceId = params[0];
1485 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001486
Ed Tanous1abe55e2018-09-05 08:30:59 -07001487 if (!verifyNames(res, parentIfaceId, ifaceId))
1488 {
1489 return;
1490 }
1491
Ed Tanous0627a2c2018-11-29 17:09:23 -08001492 bool vlanEnable = false;
1493 uint64_t vlanId = 0;
1494
1495 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1496 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001497 {
1498 return;
1499 }
1500
1501 // Get single eth interface data, and call the below callback for JSON
1502 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001503 getEthernetIfaceData(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001504 ifaceId,
Ed Tanous0627a2c2018-11-29 17:09:23 -08001505 [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001506 const bool &success, const EthernetInterfaceData &ethData,
1507 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001508 if (!success)
1509 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001510 // TODO(Pawel)consider distinguish between non existing
1511 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001512 messages::resourceNotFound(
1513 asyncResp->res, "VLAN Network Interface", ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001514
1515 return;
1516 }
1517
Ed Tanous0f74e642018-11-12 15:17:05 -08001518 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1519 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001520
Ed Tanous0627a2c2018-11-29 17:09:23 -08001521 EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable,
1522 ethData, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523 });
1524 }
1525
1526 void doDelete(crow::Response &res, const crow::Request &req,
1527 const std::vector<std::string> &params) override
1528 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001529 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001530 if (params.size() != 2)
1531 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001532 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 return;
1534 }
1535
1536 const std::string &parentIfaceId = params[0];
1537 const std::string &ifaceId = params[1];
1538
Ed Tanous4a0cb852018-10-15 07:55:04 -07001539 if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001540 {
1541 return;
1542 }
1543
1544 // Get single eth interface data, and call the below callback for JSON
1545 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001546 getEthernetIfaceData(
1547 ifaceId,
1548 [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
1549 ifaceId{std::string(ifaceId)}](
1550 const bool &success, const EthernetInterfaceData &ethData,
1551 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1552 if (success && ethData.vlan_id)
1553 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001554 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1555 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556
Jason M. Billsf12894f2018-10-09 12:45:45 -07001557 auto callback =
1558 [asyncResp](const boost::system::error_code ec) {
1559 if (ec)
1560 {
1561 messages::internalError(asyncResp->res);
1562 }
1563 };
1564 crow::connections::systemBus->async_method_call(
1565 std::move(callback), "xyz.openbmc_project.Network",
1566 std::string("/xyz/openbmc_project/network/") + ifaceId,
1567 "xyz.openbmc_project.Object.Delete", "Delete");
1568 }
1569 else
1570 {
1571 // ... otherwise return error
1572 // TODO(Pawel)consider distinguish between non existing
1573 // object, and other errors
1574 messages::resourceNotFound(
1575 asyncResp->res, "VLAN Network Interface", ifaceId);
1576 }
1577 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001579};
1580
1581/**
1582 * VlanNetworkInterfaceCollection derived class for delivering
1583 * VLANNetworkInterface Collection Schema
1584 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585class VlanNetworkInterfaceCollection : public Node
1586{
1587 public:
1588 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001590 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1591 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001592 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001593 entityPrivileges = {
1594 {boost::beast::http::verb::get, {{"Login"}}},
1595 {boost::beast::http::verb::head, {{"Login"}}},
1596 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1597 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1598 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1599 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001600 }
1601
Ed Tanous1abe55e2018-09-05 08:30:59 -07001602 private:
1603 /**
1604 * Functions triggers appropriate requests on DBus
1605 */
1606 void doGet(crow::Response &res, const crow::Request &req,
1607 const std::vector<std::string> &params) override
1608 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001609 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610 if (params.size() != 1)
1611 {
1612 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07001613 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001614 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07001615 }
1616
Ed Tanous4a0cb852018-10-15 07:55:04 -07001617 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001618
Ed Tanous4a0cb852018-10-15 07:55:04 -07001619 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001620 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001621 getEthernetIfaceList(
1622 [this, asyncResp,
1623 rootInterfaceName{std::string(rootInterfaceName)}](
1624 const bool &success,
1625 const std::vector<std::string> &iface_list) {
1626 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001628 messages::internalError(asyncResp->res);
1629 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001630 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001631 asyncResp->res.jsonValue["@odata.type"] =
1632 "#VLanNetworkInterfaceCollection."
1633 "VLanNetworkInterfaceCollection";
1634 asyncResp->res.jsonValue["@odata.context"] =
1635 "/redfish/v1/$metadata"
1636 "#VLanNetworkInterfaceCollection."
1637 "VLanNetworkInterfaceCollection";
1638 asyncResp->res.jsonValue["Name"] =
1639 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07001640
Jason M. Billsf12894f2018-10-09 12:45:45 -07001641 nlohmann::json iface_array = nlohmann::json::array();
1642
1643 for (const std::string &iface_item : iface_list)
1644 {
1645 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
1646 {
1647 iface_array.push_back(
1648 {{"@odata.id",
1649 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1650 rootInterfaceName + "/VLANs/" + iface_item}});
1651 }
1652 }
1653
1654 if (iface_array.empty())
1655 {
1656 messages::resourceNotFound(
1657 asyncResp->res, "EthernetInterface", rootInterfaceName);
1658 return;
1659 }
1660 asyncResp->res.jsonValue["Members@odata.count"] =
1661 iface_array.size();
1662 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
1663 asyncResp->res.jsonValue["@odata.id"] =
1664 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1665 rootInterfaceName + "/VLANs";
1666 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001668
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669 void doPost(crow::Response &res, const crow::Request &req,
1670 const std::vector<std::string> &params) override
1671 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001672 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 if (params.size() != 1)
1674 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001675 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 return;
1677 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001678
Ed Tanous0627a2c2018-11-29 17:09:23 -08001679 uint32_t vlanId = 0;
1680 if (!json_util::readJson(req, res, "VLANId", vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001681 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001682 return;
1683 }
1684 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07001685 auto callback = [asyncResp](const boost::system::error_code ec) {
1686 if (ec)
1687 {
1688 // TODO(ed) make more consistent error messages based on
1689 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07001690 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001691 return;
1692 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001693 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001694 };
1695 crow::connections::systemBus->async_method_call(
1696 std::move(callback), "xyz.openbmc_project.Network",
1697 "/xyz/openbmc_project/network",
1698 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08001699 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001701};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001702} // namespace redfish