blob: 71cde151fed1bfa79bcc5df96b54300c88c47839 [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;
81 std::string hostname;
82 std::string default_gateway;
83 std::string mac_address;
Ed Tanousa24526d2018-12-10 15:17:59 -080084 std::optional<uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -080085 std::vector<std::string> nameservers;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010086};
87
Ed Tanous4a0cb852018-10-15 07:55:04 -070088// Helper function that changes bits netmask notation (i.e. /24)
89// into full dot notation
90inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -070091{
Ed Tanous4a0cb852018-10-15 07:55:04 -070092 uint32_t value = 0xffffffff << (32 - bits);
93 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
94 std::to_string((value >> 16) & 0xff) + "." +
95 std::to_string((value >> 8) & 0xff) + "." +
96 std::to_string(value & 0xff);
97 return netmask;
98}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010099
Ed Tanous4a0cb852018-10-15 07:55:04 -0700100inline std::string
101 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
102 bool isIPv4)
103{
104 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700106 return "Static";
107 }
108 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
109 {
110 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700112 return "IPv4LinkLocal";
113 }
114 else
115 {
116 return "LinkLocal";
117 }
118 }
119 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
120 {
121 if (isIPv4)
122 {
123 return "DHCP";
124 }
125 else
126 {
127 return "DHCPv6";
128 }
129 }
130 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
131 {
132 return "SLAAC";
133 }
134 return "";
135}
136
137inline std::string
138 translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
139{
140 if (inputOrigin == "Static")
141 {
142 return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
143 }
144 if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
145 {
146 return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
147 }
148 if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
149 {
150 return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
151 }
152 if (inputOrigin == "SLAAC")
153 {
154 return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
155 }
156 return "";
157}
158
159inline void extractEthernetInterfaceData(const std::string &ethiface_id,
160 const GetManagedObjects &dbus_data,
161 EthernetInterfaceData &ethData)
162{
163 for (const auto &objpath : dbus_data)
164 {
Ed Tanous029573d2019-02-01 10:57:49 -0800165 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700166 {
Ed Tanous029573d2019-02-01 10:57:49 -0800167 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700169 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700171 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700173 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700175 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800176 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700177 if (mac != nullptr)
178 {
179 ethData.mac_address = *mac;
180 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700182 }
183 }
184 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
185 {
186 for (const auto &propertyPair : ifacePair.second)
187 {
188 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800190 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800191 std::get_if<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 Tanousabf2add2019-01-22 16:40:12 -0800207 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700208 if (auto_neg != nullptr)
209 {
210 ethData.auto_neg = *auto_neg;
211 }
212 }
213 else if (propertyPair.first == "Speed")
214 {
215 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800216 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700217 if (speed != nullptr)
218 {
219 ethData.speed = *speed;
220 }
221 }
Ed Tanous029573d2019-02-01 10:57:49 -0800222 else if (propertyPair.first == "NameServers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700223 {
Ed Tanous029573d2019-02-01 10:57:49 -0800224 const std::vector<std::string> *nameservers =
225 sdbusplus::message::variant_ns::get_if<
226 std::vector<std::string>>(
227 &propertyPair.second);
228 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700229 {
Ed Tanous029573d2019-02-01 10:57:49 -0800230 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700231 }
232 }
Ed Tanous029573d2019-02-01 10:57:49 -0800233 }
234 }
235 }
236 // System configuration shows up in the global namespace, so no need
237 // to check eth number
238 if (ifacePair.first ==
239 "xyz.openbmc_project.Network.SystemConfiguration")
240 {
241 for (const auto &propertyPair : ifacePair.second)
242 {
243 if (propertyPair.first == "HostName")
244 {
245 const std::string *hostname =
246 sdbusplus::message::variant_ns::get_if<std::string>(
247 &propertyPair.second);
248 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700249 {
Ed Tanous029573d2019-02-01 10:57:49 -0800250 ethData.hostname = *hostname;
251 }
252 }
253 else if (propertyPair.first == "DefaultGateway")
254 {
255 const std::string *defaultGateway =
256 sdbusplus::message::variant_ns::get_if<std::string>(
257 &propertyPair.second);
258 if (defaultGateway != nullptr)
259 {
260 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700261 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 }
263 }
264 }
265 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700267}
268
269// Helper function that extracts data for single ethernet ipv4 address
270inline void
271 extractIPData(const std::string &ethiface_id,
272 const GetManagedObjects &dbus_data,
273 boost::container::flat_set<IPv4AddressData> &ipv4_config)
274{
275 const std::string ipv4PathStart =
276 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
277
278 // Since there might be several IPv4 configurations aligned with
279 // single ethernet interface, loop over all of them
280 for (const auto &objpath : dbus_data)
281 {
282 // Check if proper pattern for object path appears
283 if (boost::starts_with(objpath.first.str, ipv4PathStart))
284 {
285 for (auto &interface : objpath.second)
286 {
287 if (interface.first == "xyz.openbmc_project.Network.IP")
288 {
289 // Instance IPv4AddressData structure, and set as
290 // appropriate
291 std::pair<
292 boost::container::flat_set<IPv4AddressData>::iterator,
293 bool>
294 it = ipv4_config.insert(
295 {objpath.first.str.substr(ipv4PathStart.size())});
296 IPv4AddressData &ipv4_address = *it.first;
297 for (auto &property : interface.second)
298 {
299 if (property.first == "Address")
300 {
301 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800302 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700303 if (address != nullptr)
304 {
305 ipv4_address.address = *address;
306 }
307 }
308 else if (property.first == "Gateway")
309 {
310 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800311 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700312 if (gateway != nullptr)
313 {
314 ipv4_address.gateway = *gateway;
315 }
316 }
317 else if (property.first == "Origin")
318 {
319 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800320 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700321 if (origin != nullptr)
322 {
323 ipv4_address.origin =
324 translateAddressOriginDbusToRedfish(*origin,
325 true);
326 }
327 }
328 else if (property.first == "PrefixLength")
329 {
330 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800331 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700332 if (mask != nullptr)
333 {
334 // convert it to the string
335 ipv4_address.netmask = getNetmask(*mask);
336 }
337 }
338 else
339 {
340 BMCWEB_LOG_ERROR
341 << "Got extra property: " << property.first
342 << " on the " << objpath.first.str << " object";
343 }
344 }
345 // Check if given address is local, or global
346 ipv4_address.linktype =
347 boost::starts_with(ipv4_address.address, "169.254.")
348 ? LinkType::Global
349 : LinkType::Local;
350 }
351 }
352 }
353 }
354}
355
356/**
357 * @brief Sets given Id on the given VLAN interface through D-Bus
358 *
359 * @param[in] ifaceId Id of VLAN interface that should be modified
360 * @param[in] inputVlanId New ID of the VLAN
361 * @param[in] callback Function that will be called after the operation
362 *
363 * @return None.
364 */
365template <typename CallbackFunc>
366void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
367 CallbackFunc &&callback)
368{
369 crow::connections::systemBus->async_method_call(
370 callback, "xyz.openbmc_project.Network",
371 std::string("/xyz/openbmc_project/network/") + ifaceId,
372 "org.freedesktop.DBus.Properties", "Set",
373 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800374 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700375}
376
377/**
378 * @brief Helper function that verifies IP address to check if it is in
379 * proper format. If bits pointer is provided, also calculates active
380 * bit count for Subnet Mask.
381 *
382 * @param[in] ip IP that will be verified
383 * @param[out] bits Calculated mask in bits notation
384 *
385 * @return true in case of success, false otherwise
386 */
387inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
388 uint8_t *bits = nullptr)
389{
390 std::vector<std::string> bytesInMask;
391
392 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700393
394 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700395 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700397 return false;
398 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399
Ed Tanous4a0cb852018-10-15 07:55:04 -0700400 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700402 *bits = 0;
403 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700404
Ed Tanous4a0cb852018-10-15 07:55:04 -0700405 char *endPtr;
406 long previousValue = 255;
407 bool firstZeroInByteHit;
408 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700410 if (byte.empty())
411 {
412 return false;
413 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414
Ed Tanous4a0cb852018-10-15 07:55:04 -0700415 // Use strtol instead of stroi to avoid exceptions
416 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417
Ed Tanous4a0cb852018-10-15 07:55:04 -0700418 // endPtr should point to the end of the string, otherwise given string
419 // is not 100% number
420 if (*endPtr != '\0')
421 {
422 return false;
423 }
424
425 // Value should be contained in byte
426 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 {
428 return false;
429 }
430
431 if (bits != nullptr)
432 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700433 // Mask has to be continuous between bytes
434 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 {
436 return false;
437 }
438
Ed Tanous4a0cb852018-10-15 07:55:04 -0700439 // Mask has to be continuous inside bytes
440 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441
Ed Tanous4a0cb852018-10-15 07:55:04 -0700442 // Count bits
443 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700445 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700447 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700449 // Continuity not preserved
450 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 }
452 else
453 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700454 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 }
456 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700457 else
458 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700459 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700461 }
462 }
463
464 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700465 }
466
Ed Tanous4a0cb852018-10-15 07:55:04 -0700467 return true;
468}
469
470/**
471 * @brief Changes IPv4 address type property (Address, Gateway)
472 *
473 * @param[in] ifaceId Id of interface whose IP should be modified
474 * @param[in] ipIdx Index of IP in input array that should be modified
475 * @param[in] ipHash DBus Hash id of modified IP
476 * @param[in] name Name of field in JSON representation
477 * @param[in] newValue New value that should be written
478 * @param[io] asyncResp Response object that will be returned to client
479 *
480 * @return true if give IP is valid and has been sent do D-Bus, false
481 * otherwise
482 */
483inline void changeIPv4AddressProperty(
484 const std::string &ifaceId, int ipIdx, const std::string &ipHash,
485 const std::string &name, const std::string &newValue,
486 const std::shared_ptr<AsyncResp> asyncResp)
487{
488 auto callback = [asyncResp, ipIdx, name{std::string(name)},
489 newValue{std::move(newValue)}](
490 const boost::system::error_code ec) {
491 if (ec)
492 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800493 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700494 }
495 else
496 {
497 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
498 }
499 };
500
501 crow::connections::systemBus->async_method_call(
502 std::move(callback), "xyz.openbmc_project.Network",
503 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
504 "org.freedesktop.DBus.Properties", "Set",
505 "xyz.openbmc_project.Network.IP", name,
Ed Tanousabf2add2019-01-22 16:40:12 -0800506 std::variant<std::string>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700507}
508
509/**
510 * @brief Changes IPv4 address origin property
511 *
512 * @param[in] ifaceId Id of interface whose IP should be modified
513 * @param[in] ipIdx Index of IP in input array that should be
514 * modified
515 * @param[in] ipHash DBus Hash id of modified IP
516 * @param[in] newValue New value in Redfish format
517 * @param[in] newValueDbus New value in D-Bus format
518 * @param[io] asyncResp Response object that will be returned to client
519 *
520 * @return true if give IP is valid and has been sent do D-Bus, false
521 * otherwise
522 */
523inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
524 const std::string &ipHash,
525 const std::string &newValue,
526 const std::string &newValueDbus,
527 const std::shared_ptr<AsyncResp> asyncResp)
528{
529 auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
530 const boost::system::error_code ec) {
531 if (ec)
532 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800533 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700534 }
535 else
536 {
537 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
538 newValue;
539 }
540 };
541
542 crow::connections::systemBus->async_method_call(
543 std::move(callback), "xyz.openbmc_project.Network",
544 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
545 "org.freedesktop.DBus.Properties", "Set",
546 "xyz.openbmc_project.Network.IP", "Origin",
Ed Tanousabf2add2019-01-22 16:40:12 -0800547 std::variant<std::string>(newValueDbus));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700548}
549
550/**
551 * @brief Modifies SubnetMask for given IP
552 *
553 * @param[in] ifaceId Id of interface whose IP should be modified
554 * @param[in] ipIdx Index of IP in input array that should be
555 * modified
556 * @param[in] ipHash DBus Hash id of modified IP
557 * @param[in] newValueStr Mask in dot notation as string
558 * @param[in] newValue Mask as PrefixLength in bitcount
559 * @param[io] asyncResp Response object that will be returned to client
560 *
561 * @return None
562 */
563inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
564 const std::string &ipHash,
565 const std::string &newValueStr,
566 uint8_t &newValue,
567 std::shared_ptr<AsyncResp> asyncResp)
568{
569 auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
570 const boost::system::error_code ec) {
571 if (ec)
572 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800573 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700574 }
575 else
576 {
577 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
578 newValueStr;
579 }
580 };
581
582 crow::connections::systemBus->async_method_call(
583 std::move(callback), "xyz.openbmc_project.Network",
584 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
585 "org.freedesktop.DBus.Properties", "Set",
586 "xyz.openbmc_project.Network.IP", "PrefixLength",
Ed Tanousabf2add2019-01-22 16:40:12 -0800587 std::variant<uint8_t>(newValue));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700588}
589
590/**
Ed Tanous4a0cb852018-10-15 07:55:04 -0700591 * @brief Deletes given IPv4
592 *
593 * @param[in] ifaceId Id of interface whose IP should be deleted
594 * @param[in] ipIdx Index of IP in input array that should be deleted
595 * @param[in] ipHash DBus Hash id of IP that should be deleted
596 * @param[io] asyncResp Response object that will be returned to client
597 *
598 * @return None
599 */
600inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
601 unsigned int ipIdx,
602 const std::shared_ptr<AsyncResp> asyncResp)
603{
604 crow::connections::systemBus->async_method_call(
605 [ipIdx, asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 if (ec)
607 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800608 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100609 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700610 else
611 {
612 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
613 }
614 },
615 "xyz.openbmc_project.Network",
616 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
617 "xyz.openbmc_project.Object.Delete", "Delete");
618}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619
Ed Tanous4a0cb852018-10-15 07:55:04 -0700620/**
621 * @brief Creates IPv4 with given data
622 *
623 * @param[in] ifaceId Id of interface whose IP should be deleted
624 * @param[in] ipIdx Index of IP in input array that should be deleted
625 * @param[in] ipHash DBus Hash id of IP that should be deleted
626 * @param[io] asyncResp Response object that will be returned to client
627 *
628 * @return None
629 */
630inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
631 uint8_t subnetMask, const std::string &gateway,
632 const std::string &address,
633 std::shared_ptr<AsyncResp> asyncResp)
634{
Ed Tanous43b761d2019-02-13 20:10:56 -0800635 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700636 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800638 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 };
641
Ed Tanous4a0cb852018-10-15 07:55:04 -0700642 crow::connections::systemBus->async_method_call(
643 std::move(createIpHandler), "xyz.openbmc_project.Network",
644 "/xyz/openbmc_project/network/" + ifaceId,
645 "xyz.openbmc_project.Network.IP.Create", "IP",
646 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
647 gateway);
648}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649
Ed Tanous4a0cb852018-10-15 07:55:04 -0700650/**
651 * Function that retrieves all properties for given Ethernet Interface
652 * Object
653 * from EntityManager Network Manager
654 * @param ethiface_id a eth interface id to query on DBus
655 * @param callback a function that shall be called to convert Dbus output
656 * into JSON
657 */
658template <typename CallbackFunc>
659void getEthernetIfaceData(const std::string &ethiface_id,
660 CallbackFunc &&callback)
661{
662 crow::connections::systemBus->async_method_call(
663 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
664 const boost::system::error_code error_code,
665 const GetManagedObjects &resp) {
666 EthernetInterfaceData ethData{};
667 boost::container::flat_set<IPv4AddressData> ipv4Data;
668
669 if (error_code)
670 {
671 callback(false, ethData, ipv4Data);
672 return;
673 }
674
675 extractEthernetInterfaceData(ethiface_id, resp, ethData);
676 extractIPData(ethiface_id, resp, ipv4Data);
677
678 // Fix global GW
679 for (IPv4AddressData &ipv4 : ipv4Data)
680 {
681 if ((ipv4.linktype == LinkType::Global) &&
682 (ipv4.gateway == "0.0.0.0"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700684 ipv4.gateway = ethData.default_gateway;
685 }
686 }
687
688 // Finally make a callback with usefull data
689 callback(true, ethData, ipv4Data);
690 },
691 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
692 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
693};
694
695/**
696 * Function that retrieves all Ethernet Interfaces available through Network
697 * Manager
698 * @param callback a function that shall be called to convert Dbus output
699 * into JSON.
700 */
701template <typename CallbackFunc>
702void getEthernetIfaceList(CallbackFunc &&callback)
703{
704 crow::connections::systemBus->async_method_call(
705 [callback{std::move(callback)}](
706 const boost::system::error_code error_code,
707 GetManagedObjects &resp) {
708 // Callback requires vector<string> to retrieve all available
709 // ethernet interfaces
710 std::vector<std::string> iface_list;
711 iface_list.reserve(resp.size());
712 if (error_code)
713 {
714 callback(false, iface_list);
715 return;
716 }
717
718 // Iterate over all retrieved ObjectPaths.
719 for (const auto &objpath : resp)
720 {
721 // And all interfaces available for certain ObjectPath.
722 for (const auto &interface : objpath.second)
723 {
724 // If interface is
725 // xyz.openbmc_project.Network.EthernetInterface, this is
726 // what we're looking for.
727 if (interface.first ==
728 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700730 // Cut out everyting until last "/", ...
731 const std::string &iface_id = objpath.first.str;
732 std::size_t last_pos = iface_id.rfind("/");
733 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700735 // and put it into output vector.
736 iface_list.emplace_back(
737 iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 }
739 }
740 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700741 }
742 // Finally make a callback with useful data
743 callback(true, iface_list);
744 },
745 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
746 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100747};
748
749/**
750 * EthernetCollection derived class for delivering Ethernet Collection Schema
751 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752class EthernetCollection : public Node
753{
754 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700755 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700757 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 entityPrivileges = {
760 {boost::beast::http::verb::get, {{"Login"}}},
761 {boost::beast::http::verb::head, {{"Login"}}},
762 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
763 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
764 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
765 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
766 }
767
768 private:
769 /**
770 * Functions triggers appropriate requests on DBus
771 */
772 void doGet(crow::Response &res, const crow::Request &req,
773 const std::vector<std::string> &params) override
774 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800775 res.jsonValue["@odata.type"] =
776 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
777 res.jsonValue["@odata.context"] =
778 "/redfish/v1/"
779 "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
780 res.jsonValue["@odata.id"] =
781 "/redfish/v1/Managers/bmc/EthernetInterfaces";
782 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
783 res.jsonValue["Description"] =
784 "Collection of EthernetInterfaces for this Manager";
785
Ed Tanous4a0cb852018-10-15 07:55:04 -0700786 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -0700788 getEthernetIfaceList(
789 [&res](const bool &success,
790 const std::vector<std::string> &iface_list) {
791 if (!success)
792 {
793 messages::internalError(res);
794 res.end();
795 return;
796 }
797
798 nlohmann::json &iface_array = res.jsonValue["Members"];
799 iface_array = nlohmann::json::array();
800 for (const std::string &iface_item : iface_list)
801 {
802 iface_array.push_back(
803 {{"@odata.id",
804 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
805 iface_item}});
806 }
807
808 res.jsonValue["Members@odata.count"] = iface_array.size();
809 res.jsonValue["@odata.id"] =
810 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 res.end();
Jason M. Billsf12894f2018-10-09 12:45:45 -0700812 });
Ed Tanous4a0cb852018-10-15 07:55:04 -0700813 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100814};
815
816/**
817 * EthernetInterface derived class for delivering Ethernet Schema
818 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819class EthernetInterface : public Node
820{
821 public:
822 /*
823 * Default Constructor
824 */
Ed Tanous4a0cb852018-10-15 07:55:04 -0700825 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700827 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 std::string())
829 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 entityPrivileges = {
831 {boost::beast::http::verb::get, {{"Login"}}},
832 {boost::beast::http::verb::head, {{"Login"}}},
833 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
834 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
835 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
836 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +0200837 }
838
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 // TODO(kkowalsk) Find a suitable class/namespace for this
Ed Tanous0627a2c2018-11-29 17:09:23 -0800840 static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable,
841 uint64_t vlanId,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700842 const EthernetInterfaceData &ethData,
843 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700845 if (!ethData.vlan_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
847 // This interface is not a VLAN. Cannot do anything with it
848 // TODO(kkowalsk) Change this message
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800849 messages::propertyNotWritable(asyncResp->res, "VLANEnable");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 return;
852 }
853
854 // VLAN is configured on the interface
Ed Tanous0627a2c2018-11-29 17:09:23 -0800855 if (vlanEnable == true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 {
857 // Change VLAN Id
Ed Tanous0627a2c2018-11-29 17:09:23 -0800858 asyncResp->res.jsonValue["VLANId"] = vlanId;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700859 auto callback = [asyncResp](const boost::system::error_code ec) {
860 if (ec)
861 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700862 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700863 }
864 else
865 {
866 asyncResp->res.jsonValue["VLANEnable"] = true;
867 }
868 };
869 crow::connections::systemBus->async_method_call(
870 std::move(callback), "xyz.openbmc_project.Network",
871 "/xyz/openbmc_project/network/" + ifaceId,
872 "org.freedesktop.DBus.Properties", "Set",
873 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800874 std::variant<uint32_t>(vlanId));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700876 else
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700878 auto callback = [asyncResp](const boost::system::error_code ec) {
879 if (ec)
880 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700881 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700882 return;
883 }
884 asyncResp->res.jsonValue["VLANEnable"] = false;
885 };
886
887 crow::connections::systemBus->async_method_call(
888 std::move(callback), "xyz.openbmc_project.Network",
889 "/xyz/openbmc_project/network/" + ifaceId,
890 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 }
892 }
893
894 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800895 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700896 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -0800898 asyncResp->res.jsonValue["HostName"] = hostname;
899 crow::connections::systemBus->async_method_call(
900 [asyncResp](const boost::system::error_code ec) {
901 if (ec)
902 {
903 messages::internalError(asyncResp->res);
904 }
905 },
906 "xyz.openbmc_project.Network",
907 "/xyz/openbmc_project/network/config",
908 "org.freedesktop.DBus.Properties", "Set",
909 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -0800910 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 }
912
Ed Tanous4a0cb852018-10-15 07:55:04 -0700913 void handleIPv4Patch(
Ed Tanous537174c2018-12-10 15:09:31 -0800914 const std::string &ifaceId, std::vector<nlohmann::json> &input,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700915 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
916 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700917 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700918 int entryIdx = 0;
919 boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
920 ipv4Data.begin();
Ed Tanous537174c2018-12-10 15:09:31 -0800921 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700923 std::string pathString =
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800924 "IPv4Addresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700925
Ratan Gupta9474b372019-03-01 15:13:37 +0530926 if (thisJson.empty())
927 {
928 if (thisData != ipv4Data.end())
929 {
930 thisData++;
931 }
932 else
933 {
934 messages::propertyMissing(asyncResp->res,
935 pathString + "/Address");
936 return;
937 // TODO Not sure about the property where value is
938 // list and if unable to update one of the
939 // list value then should we proceed further or
940 // break there, would ask in the redfish forum
941 // till then we stop processing the next list item.
942 }
943 entryIdx++;
944 continue; // not an error as per the redfish spec.
945 }
946
Ed Tanous537174c2018-12-10 15:09:31 -0800947 std::optional<std::string> address;
948 std::optional<std::string> addressOrigin;
949 std::optional<std::string> subnetMask;
950 std::optional<std::string> gateway;
951
952 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
953 address, "AddressOrigin", addressOrigin,
954 "SubnetMask", subnetMask, "Gateway",
955 gateway))
956 {
957 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700958 }
959
Ed Tanous537174c2018-12-10 15:09:31 -0800960 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 {
Ed Tanous537174c2018-12-10 15:09:31 -0800962 if (!ipv4VerifyIpAndGetBitcount(*address))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700963 {
Ed Tanous537174c2018-12-10 15:09:31 -0800964 messages::propertyValueFormatError(asyncResp->res, *address,
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800965 pathString + "/Address");
Ed Tanous537174c2018-12-10 15:09:31 -0800966 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700967 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700969
Ed Tanous537174c2018-12-10 15:09:31 -0800970 uint8_t prefixLength = 0;
971 if (subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700972 {
Ed Tanous537174c2018-12-10 15:09:31 -0800973 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
Ed Tanous4a0cb852018-10-15 07:55:04 -0700974 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700975 messages::propertyValueFormatError(
Ed Tanous537174c2018-12-10 15:09:31 -0800976 asyncResp->res, *subnetMask,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700977 pathString + "/SubnetMask");
Ed Tanous537174c2018-12-10 15:09:31 -0800978 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700979 }
980 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700981 std::string addressOriginInDBusFormat;
Ed Tanous537174c2018-12-10 15:09:31 -0800982 if (addressOrigin)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700983 {
Ed Tanous537174c2018-12-10 15:09:31 -0800984 // Get Address origin in proper format
985 addressOriginInDBusFormat =
986 translateAddressOriginRedfishToDbus(*addressOrigin);
987 if (addressOriginInDBusFormat.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -0700988 {
Ed Tanous537174c2018-12-10 15:09:31 -0800989 messages::propertyValueNotInList(
990 asyncResp->res, *addressOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700991 pathString + "/AddressOrigin");
Ed Tanous537174c2018-12-10 15:09:31 -0800992 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700993 }
994 }
995
Ed Tanous537174c2018-12-10 15:09:31 -0800996 if (gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700997 {
Ed Tanous537174c2018-12-10 15:09:31 -0800998 if (!ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanous4a0cb852018-10-15 07:55:04 -0700999 {
Ed Tanous537174c2018-12-10 15:09:31 -08001000 messages::propertyValueFormatError(asyncResp->res, *gateway,
1001 pathString + "/Gateway");
1002 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001003 }
1004 }
1005
1006 // if a vlan already exists, modify the existing
1007 if (thisData != ipv4Data.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008 {
1009 // Existing object that should be modified/deleted/remain
1010 // unchanged
Ed Tanous4a0cb852018-10-15 07:55:04 -07001011 if (thisJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001013 auto callback = [entryIdx{std::to_string(entryIdx)},
1014 asyncResp](
1015 const boost::system::error_code ec) {
1016 if (ec)
1017 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001018 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001019 return;
1020 }
1021 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
1022 nullptr;
1023 };
1024 crow::connections::systemBus->async_method_call(
1025 std::move(callback), "xyz.openbmc_project.Network",
1026 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1027 thisData->id,
1028 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001030 else if (thisJson.is_object())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001031 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001032 // Apply changes
Ed Tanous537174c2018-12-10 15:09:31 -08001033 if (address)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001034 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001035 auto callback =
Ed Tanous537174c2018-12-10 15:09:31 -08001036 [asyncResp, entryIdx, address = *address](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001037 const boost::system::error_code ec) {
1038 if (ec)
1039 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001040 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001041 return;
1042 }
Ratan Gupta82fd90f2019-03-07 21:09:25 +05301043 asyncResp->res.jsonValue["IPv4Addresses"]
1044 [entryIdx]["Address"] =
1045 address;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001046 };
1047
1048 crow::connections::systemBus->async_method_call(
1049 std::move(callback), "xyz.openbmc_project.Network",
1050 "/xyz/openbmc_project/network/" + ifaceId +
1051 "/ipv4/" + thisData->id,
1052 "org.freedesktop.DBus.Properties", "Set",
1053 "xyz.openbmc_project.Network.IP", "Address",
Ed Tanous537174c2018-12-10 15:09:31 -08001054 std::variant<std::string>(*address));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001055 }
1056
Ed Tanous537174c2018-12-10 15:09:31 -08001057 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001058 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001059 changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
Ed Tanous537174c2018-12-10 15:09:31 -08001060 thisData->id, *subnetMask,
1061 prefixLength, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001062 }
1063
Ed Tanous537174c2018-12-10 15:09:31 -08001064 if (addressOrigin)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001065 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001066 changeIPv4Origin(ifaceId, entryIdx, thisData->id,
Ed Tanous537174c2018-12-10 15:09:31 -08001067 *addressOrigin,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001068 addressOriginInDBusFormat, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001069 }
1070
Ed Tanous537174c2018-12-10 15:09:31 -08001071 if (gateway)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001072 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001073 auto callback =
1074 [asyncResp, entryIdx,
Ed Tanous537174c2018-12-10 15:09:31 -08001075 gateway{std::string(*gateway)}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001076 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 }
Ratan Gupta82fd90f2019-03-07 21:09:25 +05301082 asyncResp->res.jsonValue["IPv4Addresses"]
1083 [entryIdx]["Gateway"] =
Ed Tanous537174c2018-12-10 15:09:31 -08001084 std::move(gateway);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001085 };
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", "Gateway",
Ed Tanous537174c2018-12-10 15:09:31 -08001093 std::variant<std::string>(*gateway));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001094 }
1095 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001096 thisData++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001097 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001098 else
1099 {
1100 // Create IPv4 with provided data
Ed Tanous537174c2018-12-10 15:09:31 -08001101 if (!gateway)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001102 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001103 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001104 pathString + "/Gateway");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001105 continue;
1106 }
1107
Ed Tanous537174c2018-12-10 15:09:31 -08001108 if (!address)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001109 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001110 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001111 pathString + "/Address");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001112 continue;
1113 }
1114
Ed Tanous537174c2018-12-10 15:09:31 -08001115 if (!subnetMask)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001116 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001117 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001118 pathString + "/SubnetMask");
Ed Tanous4a0cb852018-10-15 07:55:04 -07001119 continue;
1120 }
1121
Ed Tanous537174c2018-12-10 15:09:31 -08001122 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1123 asyncResp);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001124 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
1125 }
1126 entryIdx++;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001127 }
1128 }
1129
Ed Tanous0f74e642018-11-12 15:17:05 -08001130 void parseInterfaceData(
1131 nlohmann::json &json_response, const std::string &iface_id,
1132 const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001133 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001134 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001135 json_response["Id"] = iface_id;
1136 json_response["@odata.id"] =
1137 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Ed Tanous029573d2019-02-01 10:57:49 -08001138 json_response["InterfaceEnabled"] = true;
1139 if (ethData.speed == 0)
1140 {
1141 json_response["LinkStatus"] = "NoLink";
1142 json_response["Status"] = {
1143 {"Health", "OK"},
1144 {"State", "Disabled"},
1145 };
1146 }
1147 else
1148 {
1149 json_response["LinkStatus"] = "LinkUp";
1150 json_response["Status"] = {
1151 {"Health", "OK"},
1152 {"State", "Enabled"},
1153 };
1154 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001155 json_response["SpeedMbps"] = ethData.speed;
1156 json_response["MACAddress"] = ethData.mac_address;
1157 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001158 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001159 json_response["HostName"] = ethData.hostname;
1160 }
1161
1162 nlohmann::json &vlanObj = json_response["VLAN"];
1163 if (ethData.vlan_id)
1164 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001165 vlanObj["VLANEnable"] = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001166 vlanObj["VLANId"] = *ethData.vlan_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001167 }
1168 else
1169 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001170 vlanObj["VLANEnable"] = false;
1171 vlanObj["VLANId"] = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001172 }
Ed Tanous029573d2019-02-01 10:57:49 -08001173 json_response["NameServers"] = ethData.nameservers;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001174
Ed Tanous4a0cb852018-10-15 07:55:04 -07001175 if (ipv4Data.size() > 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001176 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001177 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1178 ipv4_array = nlohmann::json::array();
1179 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001180 {
Ed Tanous029573d2019-02-01 10:57:49 -08001181 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1182 {"SubnetMask", ipv4_config.netmask},
1183 {"Address", ipv4_config.address},
1184 {"Gateway", ipv4_config.gateway}});
Ed Tanous1abe55e2018-09-05 08:30:59 -07001185 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001186 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001187 }
1188
1189 /**
1190 * Functions triggers appropriate requests on DBus
1191 */
1192 void doGet(crow::Response &res, const crow::Request &req,
1193 const std::vector<std::string> &params) override
1194 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001195 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001196 if (params.size() != 1)
1197 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001198 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001199 return;
1200 }
1201
Ed Tanous4a0cb852018-10-15 07:55:04 -07001202 getEthernetIfaceData(
1203 params[0],
1204 [this, asyncResp, iface_id{std::string(params[0])}](
1205 const bool &success, const EthernetInterfaceData &ethData,
1206 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1207 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001208 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001209 // TODO(Pawel)consider distinguish between non existing
1210 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001211 messages::resourceNotFound(asyncResp->res,
1212 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001213 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001214 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001215 asyncResp->res.jsonValue["@odata.type"] =
1216 "#EthernetInterface.v1_2_0.EthernetInterface";
1217 asyncResp->res.jsonValue["@odata.context"] =
1218 "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
1219 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1220 asyncResp->res.jsonValue["Description"] =
1221 "Management Network Interface";
1222
1223 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1224 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001225 });
1226 }
1227
1228 void doPatch(crow::Response &res, const crow::Request &req,
1229 const std::vector<std::string> &params) override
1230 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001231 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001232 if (params.size() != 1)
1233 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001234 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 return;
1236 }
1237
Ed Tanous4a0cb852018-10-15 07:55:04 -07001238 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001239
Ed Tanous0627a2c2018-11-29 17:09:23 -08001240 std::optional<nlohmann::json> vlan;
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001241 std::optional<std::string> hostname;
Ed Tanous537174c2018-12-10 15:09:31 -08001242 std::optional<std::vector<nlohmann::json>> ipv4Addresses;
1243 std::optional<std::vector<nlohmann::json>> ipv6Addresses;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001244
1245 if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
1246 "IPv4Addresses", ipv4Addresses,
1247 "IPv6Addresses", ipv6Addresses))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248 {
1249 return;
1250 }
Ratan Guptaf15aad32019-03-01 13:41:13 +05301251
1252 std::optional<uint64_t> vlanId;
1253 std::optional<bool> vlanEnable;
1254
Ed Tanous0627a2c2018-11-29 17:09:23 -08001255 if (vlan)
1256 {
1257 if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable,
1258 "VLANId", vlanId))
1259 {
1260 return;
1261 }
1262 // Need both vlanId and vlanEnable to service this request
1263 if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1264 {
1265 if (vlanId)
1266 {
1267 messages::propertyMissing(asyncResp->res, "VLANEnable");
1268 }
1269 else
1270 {
1271 messages::propertyMissing(asyncResp->res, "VLANId");
1272 }
1273
1274 return;
1275 }
1276 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001277
Ed Tanous4a0cb852018-10-15 07:55:04 -07001278 // Get single eth interface data, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001279 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001280 getEthernetIfaceData(
1281 iface_id,
Ed Tanous0627a2c2018-11-29 17:09:23 -08001282 [this, asyncResp, iface_id, vlanId, vlanEnable,
1283 hostname = std::move(hostname),
1284 ipv4Addresses = std::move(ipv4Addresses),
1285 ipv6Addresses = std::move(ipv6Addresses)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001286 const bool &success, const EthernetInterfaceData &ethData,
1287 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001288 if (!success)
1289 {
1290 // ... otherwise return error
1291 // TODO(Pawel)consider distinguish between non existing
1292 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001293 messages::resourceNotFound(
1294 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001295 return;
1296 }
1297
Ed Tanous0f74e642018-11-12 15:17:05 -08001298 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1299 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001300
Ed Tanous0627a2c2018-11-29 17:09:23 -08001301 if (vlanId && vlanEnable)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001302 {
Ed Tanous0627a2c2018-11-29 17:09:23 -08001303 handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData,
1304 asyncResp);
1305 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001306
Ed Tanous0627a2c2018-11-29 17:09:23 -08001307 if (hostname)
1308 {
1309 handleHostnamePatch(*hostname, asyncResp);
1310 }
1311
1312 if (ipv4Addresses)
1313 {
Ed Tanous537174c2018-12-10 15:09:31 -08001314 // TODO(ed) for some reason the capture of ipv4Addresses
1315 // above is returning a const value, not a non-const value.
1316 // This doesn't really work for us, as we need to be able to
1317 // efficiently move out the intermedia nlohmann::json
1318 // objects. This makes a copy of the structure, and operates
1319 // on that, but could be done more efficiently
1320 std::vector<nlohmann::json> ipv4 =
1321 std::move(*ipv4Addresses);
1322 handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001323 }
1324
1325 if (ipv6Addresses)
1326 {
1327 // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1328 messages::propertyNotWritable(asyncResp->res,
1329 "IPv6Addresses");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001330 }
1331 });
1332 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001333};
1334
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001335/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001336 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1337 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001338 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001339class VlanNetworkInterface : public Node
1340{
1341 public:
1342 /*
1343 * Default Constructor
1344 */
1345 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001346 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001347 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001348 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001349 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001350 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001351 entityPrivileges = {
1352 {boost::beast::http::verb::get, {{"Login"}}},
1353 {boost::beast::http::verb::head, {{"Login"}}},
1354 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1355 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1356 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1357 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001358 }
1359
Ed Tanous1abe55e2018-09-05 08:30:59 -07001360 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001361 void parseInterfaceData(
1362 nlohmann::json &json_response, const std::string &parent_iface_id,
1363 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001364 const boost::container::flat_set<IPv4AddressData> &ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001365 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001366 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001367 json_response["Id"] = iface_id;
1368 json_response["@odata.id"] =
1369 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1370 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001371
Ed Tanous4a0cb852018-10-15 07:55:04 -07001372 json_response["VLANEnable"] = true;
1373 if (ethData.vlan_id)
1374 {
1375 json_response["VLANId"] = *ethData.vlan_id;
1376 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07001377 }
1378
Ed Tanous1abe55e2018-09-05 08:30:59 -07001379 bool verifyNames(crow::Response &res, const std::string &parent,
1380 const std::string &iface)
1381 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001382 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383 if (!boost::starts_with(iface, parent + "_"))
1384 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001385 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1386 iface);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001387 return false;
1388 }
1389 else
1390 {
1391 return true;
1392 }
1393 }
1394
1395 /**
1396 * Functions triggers appropriate requests on DBus
1397 */
1398 void doGet(crow::Response &res, const crow::Request &req,
1399 const std::vector<std::string> &params) override
1400 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001401 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1402 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07001403 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1404 // Check if there is required param, truly entering this shall be
1405 // impossible.
1406 if (params.size() != 2)
1407 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001408 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001410 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001411 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001412
Ed Tanous4a0cb852018-10-15 07:55:04 -07001413 const std::string &parent_iface_id = params[0];
1414 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08001415 res.jsonValue["@odata.type"] =
1416 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1417 res.jsonValue["@odata.context"] =
1418 "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1419 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001420
Ed Tanous4a0cb852018-10-15 07:55:04 -07001421 if (!verifyNames(res, parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 {
1423 return;
1424 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02001425
Ed Tanous1abe55e2018-09-05 08:30:59 -07001426 // Get single eth interface data, and call the below callback for JSON
1427 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001428 getEthernetIfaceData(
1429 iface_id,
1430 [this, asyncResp, parent_iface_id, iface_id](
1431 const bool &success, const EthernetInterfaceData &ethData,
1432 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1433 if (success && ethData.vlan_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001434 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001435 parseInterfaceData(asyncResp->res.jsonValue,
1436 parent_iface_id, iface_id, ethData,
1437 ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001438 }
1439 else
1440 {
1441 // ... otherwise return error
1442 // TODO(Pawel)consider distinguish between non existing
1443 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001444 messages::resourceNotFound(
1445 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001446 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001447 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001448 }
1449
Ed Tanous1abe55e2018-09-05 08:30:59 -07001450 void doPatch(crow::Response &res, const crow::Request &req,
1451 const std::vector<std::string> &params) override
1452 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001453 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001454 if (params.size() != 2)
1455 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001456 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001457 return;
1458 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001459
Ed Tanous1abe55e2018-09-05 08:30:59 -07001460 const std::string &parentIfaceId = params[0];
1461 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001462
Ed Tanous1abe55e2018-09-05 08:30:59 -07001463 if (!verifyNames(res, parentIfaceId, ifaceId))
1464 {
1465 return;
1466 }
1467
Ed Tanous0627a2c2018-11-29 17:09:23 -08001468 bool vlanEnable = false;
1469 uint64_t vlanId = 0;
1470
1471 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
1472 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001473 {
1474 return;
1475 }
1476
1477 // Get single eth interface data, and call the below callback for JSON
1478 // preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001479 getEthernetIfaceData(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001480 ifaceId,
Ed Tanous0627a2c2018-11-29 17:09:23 -08001481 [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001482 const bool &success, const EthernetInterfaceData &ethData,
1483 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001484 if (!success)
1485 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001486 // TODO(Pawel)consider distinguish between non existing
1487 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001488 messages::resourceNotFound(
1489 asyncResp->res, "VLAN Network Interface", ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001490
1491 return;
1492 }
1493
Ed Tanous0f74e642018-11-12 15:17:05 -08001494 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1495 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001496
Ed Tanous0627a2c2018-11-29 17:09:23 -08001497 EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable,
1498 ethData, asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 });
1500 }
1501
1502 void doDelete(crow::Response &res, const crow::Request &req,
1503 const std::vector<std::string> &params) override
1504 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001505 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001506 if (params.size() != 2)
1507 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001508 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509 return;
1510 }
1511
1512 const std::string &parentIfaceId = params[0];
1513 const std::string &ifaceId = params[1];
1514
Ed Tanous4a0cb852018-10-15 07:55:04 -07001515 if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001516 {
1517 return;
1518 }
1519
1520 // Get single eth interface data, and call the below callback for JSON
1521 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001522 getEthernetIfaceData(
1523 ifaceId,
1524 [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
1525 ifaceId{std::string(ifaceId)}](
1526 const bool &success, const EthernetInterfaceData &ethData,
1527 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1528 if (success && ethData.vlan_id)
1529 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001530 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
1531 ifaceId, ethData, ipv4Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532
Jason M. Billsf12894f2018-10-09 12:45:45 -07001533 auto callback =
1534 [asyncResp](const boost::system::error_code ec) {
1535 if (ec)
1536 {
1537 messages::internalError(asyncResp->res);
1538 }
1539 };
1540 crow::connections::systemBus->async_method_call(
1541 std::move(callback), "xyz.openbmc_project.Network",
1542 std::string("/xyz/openbmc_project/network/") + ifaceId,
1543 "xyz.openbmc_project.Object.Delete", "Delete");
1544 }
1545 else
1546 {
1547 // ... otherwise return error
1548 // TODO(Pawel)consider distinguish between non existing
1549 // object, and other errors
1550 messages::resourceNotFound(
1551 asyncResp->res, "VLAN Network Interface", ifaceId);
1552 }
1553 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001554 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001555};
1556
1557/**
1558 * VlanNetworkInterfaceCollection derived class for delivering
1559 * VLANNetworkInterface Collection Schema
1560 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561class VlanNetworkInterfaceCollection : public Node
1562{
1563 public:
1564 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001565 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001566 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1567 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001569 entityPrivileges = {
1570 {boost::beast::http::verb::get, {{"Login"}}},
1571 {boost::beast::http::verb::head, {{"Login"}}},
1572 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1573 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1574 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1575 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001576 }
1577
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 private:
1579 /**
1580 * Functions triggers appropriate requests on DBus
1581 */
1582 void doGet(crow::Response &res, const crow::Request &req,
1583 const std::vector<std::string> &params) override
1584 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001585 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001586 if (params.size() != 1)
1587 {
1588 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07001589 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07001591 }
1592
Ed Tanous4a0cb852018-10-15 07:55:04 -07001593 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001594
Ed Tanous4a0cb852018-10-15 07:55:04 -07001595 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001596 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001597 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08001598 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07001599 const bool &success,
1600 const std::vector<std::string> &iface_list) {
1601 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001602 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001603 messages::internalError(asyncResp->res);
1604 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001605 }
Ed Tanous0f74e642018-11-12 15:17:05 -08001606 asyncResp->res.jsonValue["@odata.type"] =
1607 "#VLanNetworkInterfaceCollection."
1608 "VLanNetworkInterfaceCollection";
1609 asyncResp->res.jsonValue["@odata.context"] =
1610 "/redfish/v1/$metadata"
1611 "#VLanNetworkInterfaceCollection."
1612 "VLanNetworkInterfaceCollection";
1613 asyncResp->res.jsonValue["Name"] =
1614 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07001615
Jason M. Billsf12894f2018-10-09 12:45:45 -07001616 nlohmann::json iface_array = nlohmann::json::array();
1617
1618 for (const std::string &iface_item : iface_list)
1619 {
1620 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
1621 {
1622 iface_array.push_back(
1623 {{"@odata.id",
1624 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1625 rootInterfaceName + "/VLANs/" + iface_item}});
1626 }
1627 }
1628
1629 if (iface_array.empty())
1630 {
1631 messages::resourceNotFound(
1632 asyncResp->res, "EthernetInterface", rootInterfaceName);
1633 return;
1634 }
1635 asyncResp->res.jsonValue["Members@odata.count"] =
1636 iface_array.size();
1637 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
1638 asyncResp->res.jsonValue["@odata.id"] =
1639 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1640 rootInterfaceName + "/VLANs";
1641 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001643
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644 void doPost(crow::Response &res, const crow::Request &req,
1645 const std::vector<std::string> &params) override
1646 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001647 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001648 if (params.size() != 1)
1649 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001650 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 return;
1652 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001653
Ed Tanous0627a2c2018-11-29 17:09:23 -08001654 uint32_t vlanId = 0;
1655 if (!json_util::readJson(req, res, "VLANId", vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001657 return;
1658 }
1659 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07001660 auto callback = [asyncResp](const boost::system::error_code ec) {
1661 if (ec)
1662 {
1663 // TODO(ed) make more consistent error messages based on
1664 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07001665 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001666 return;
1667 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001668 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001669 };
1670 crow::connections::systemBus->async_method_call(
1671 std::move(callback), "xyz.openbmc_project.Network",
1672 "/xyz/openbmc_project/network",
1673 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08001674 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001675 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001676};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677} // namespace redfish