blob: 0a2a1858b78df290627074ebca6081bdd9946eb3 [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous1abe55e2018-09-05 08:30:59 -070018#include <boost/container/flat_map.hpp>
Ed Tanous4a0cb852018-10-15 07:55:04 -070019#include <boost/container/flat_set.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020020#include <dbus_singleton.hpp>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020021#include <error_messages.hpp>
Kowalski, Kamil179db1d2018-04-23 11:12:41 +020022#include <node.hpp>
Ed Tanousa24526d2018-12-10 15:17:59 -080023#include <optional>
Kowalski, Kamil588c3f02018-04-03 14:55:27 +020024#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080025#include <variant>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace redfish
28{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010029
30/**
31 * DBus types primitives for several generic DBus interfaces
32 * TODO(Pawel) consider move this to separate file into boost::dbus
33 */
Ed Tanousaa2e59c2018-04-12 12:17:20 -070034using PropertiesMapType = boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080035 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36 int32_t, uint32_t, int64_t, uint64_t, double>>;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010037
Ed Tanous4a0cb852018-10-15 07:55:04 -070038using GetManagedObjects = std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070039 sdbusplus::message::object_path,
Ed Tanous4a0cb852018-10-15 07:55:04 -070040 std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -070041 std::string,
42 boost::container::flat_map<
Ed Tanous029573d2019-02-01 10:57:49 -080043 std::string, sdbusplus::message::variant<
44 std::string, bool, uint8_t, int16_t, uint16_t,
45 int32_t, uint32_t, int64_t, uint64_t, double,
46 std::vector<std::string>>>>>>>;
Ed Tanous4a0cb852018-10-15 07:55:04 -070047
48enum class LinkType
49{
50 Local,
51 Global
52};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010053
54/**
55 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010056 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070057struct IPv4AddressData
58{
59 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070060 std::string address;
61 std::string domain;
62 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 std::string netmask;
64 std::string origin;
Ed Tanous4a0cb852018-10-15 07:55:04 -070065 LinkType linktype;
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 bool operator<(const IPv4AddressData &obj) const
68 {
Ed Tanous4a0cb852018-10-15 07:55:04 -070069 return id < obj.id;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
81 uint8_t prefixLength;
82
83 bool operator<(const IPv6AddressData &obj) const
84 {
85 return id < obj.id;
86 }
87};
88/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010089 * Structure for keeping basic single Ethernet Interface information
90 * available from DBus
91 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070092struct EthernetInterfaceData
93{
Ed Tanous4a0cb852018-10-15 07:55:04 -070094 uint32_t speed;
95 bool auto_neg;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -070096 bool DNSEnabled;
97 bool NTPEnabled;
98 bool HostNameEnabled;
99 bool SendHostNameEnabled;
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800100 bool linkUp;
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700101 bool nicEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700102 std::string DHCPEnabled;
103 std::string operatingMode;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700104 std::string hostname;
105 std::string default_gateway;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500106 std::string ipv6_default_gateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700107 std::string mac_address;
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500108 std::vector<std::uint32_t> vlan_id;
Ed Tanous029573d2019-02-01 10:57:49 -0800109 std::vector<std::string> nameservers;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800110 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100111};
112
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700113struct DHCPParameters
114{
115 std::optional<bool> dhcpv4Enabled;
116 std::optional<bool> useDNSServers;
117 std::optional<bool> useNTPServers;
118 std::optional<bool> useUseDomainName;
119 std::optional<std::string> dhcpv6OperatingMode;
120};
121
Ed Tanous4a0cb852018-10-15 07:55:04 -0700122// Helper function that changes bits netmask notation (i.e. /24)
123// into full dot notation
124inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700126 uint32_t value = 0xffffffff << (32 - bits);
127 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
128 std::to_string((value >> 16) & 0xff) + "." +
129 std::to_string((value >> 8) & 0xff) + "." +
130 std::to_string(value & 0xff);
131 return netmask;
132}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100133
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700134inline bool translateDHCPEnabledToBool(const std::string &inputDHCP,
135 bool isIPv4)
136{
137 if (isIPv4)
138 {
139 return (
140 (inputDHCP ==
141 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4") ||
142 (inputDHCP ==
143 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
144 }
145 return ((inputDHCP ==
146 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6") ||
147 (inputDHCP ==
148 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
149}
150
151inline std::string GetDHCPEnabledEnumeration(bool isIPv4, bool isIPv6)
152{
153 if (isIPv4 && isIPv6)
154 {
155 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both";
156 }
157 else if (isIPv4)
158 {
159 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4";
160 }
161 else if (isIPv6)
162 {
163 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6";
164 }
165 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.none";
166}
167
Ed Tanous4a0cb852018-10-15 07:55:04 -0700168inline std::string
169 translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
170 bool isIPv4)
171{
172 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700174 return "Static";
175 }
176 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
177 {
178 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700180 return "IPv4LinkLocal";
181 }
182 else
183 {
184 return "LinkLocal";
185 }
186 }
187 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
188 {
189 if (isIPv4)
190 {
191 return "DHCP";
192 }
193 else
194 {
195 return "DHCPv6";
196 }
197 }
198 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
199 {
200 return "SLAAC";
201 }
202 return "";
203}
204
Ed Tanous4c9afe42019-05-03 16:59:57 -0700205inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700206 const GetManagedObjects &dbus_data,
207 EthernetInterfaceData &ethData)
208{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700209 bool idFound = false;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700210 for (const auto &objpath : dbus_data)
211 {
Ed Tanous029573d2019-02-01 10:57:49 -0800212 for (const auto &ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700213 {
Ed Tanous029573d2019-02-01 10:57:49 -0800214 if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700216 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700217 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700219 for (const auto &propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700221 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700222 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700223 const std::string *mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800224 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700225 if (mac != nullptr)
226 {
227 ethData.mac_address = *mac;
228 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700230 }
231 }
232 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
233 {
234 for (const auto &propertyPair : ifacePair.second)
235 {
236 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237 {
Ed Tanous1b6b96c2018-11-30 11:35:41 -0800238 const uint32_t *id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800239 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700240 if (id != nullptr)
241 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -0500242 ethData.vlan_id.push_back(*id);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700243 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700245 }
246 }
247 else if (ifacePair.first ==
248 "xyz.openbmc_project.Network.EthernetInterface")
249 {
250 for (const auto &propertyPair : ifacePair.second)
251 {
252 if (propertyPair.first == "AutoNeg")
253 {
254 const bool *auto_neg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800255 std::get_if<bool>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700256 if (auto_neg != nullptr)
257 {
258 ethData.auto_neg = *auto_neg;
259 }
260 }
261 else if (propertyPair.first == "Speed")
262 {
263 const uint32_t *speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800264 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700265 if (speed != nullptr)
266 {
267 ethData.speed = *speed;
268 }
269 }
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800270 else if (propertyPair.first == "LinkUp")
271 {
272 const bool *linkUp =
273 std::get_if<bool>(&propertyPair.second);
274 if (linkUp != nullptr)
275 {
276 ethData.linkUp = *linkUp;
277 }
278 }
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700279 else if (propertyPair.first == "NICEnabled")
280 {
281 const bool *nicEnabled =
282 std::get_if<bool>(&propertyPair.second);
283 if (nicEnabled != nullptr)
284 {
285 ethData.nicEnabled = *nicEnabled;
286 }
287 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500288 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700289 {
Ed Tanous029573d2019-02-01 10:57:49 -0800290 const std::vector<std::string> *nameservers =
291 sdbusplus::message::variant_ns::get_if<
292 std::vector<std::string>>(
293 &propertyPair.second);
294 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700295 {
Ed Tanous029573d2019-02-01 10:57:49 -0800296 ethData.nameservers = std::move(*nameservers);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700297 }
298 }
manojkiraneda2a133282019-02-19 13:09:43 +0530299 else if (propertyPair.first == "DHCPEnabled")
300 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700301 const std::string *DHCPEnabled =
302 std::get_if<std::string>(&propertyPair.second);
manojkiraneda2a133282019-02-19 13:09:43 +0530303 if (DHCPEnabled != nullptr)
304 {
305 ethData.DHCPEnabled = *DHCPEnabled;
306 }
307 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800308 else if (propertyPair.first == "DomainName")
309 {
310 const std::vector<std::string> *domainNames =
311 sdbusplus::message::variant_ns::get_if<
312 std::vector<std::string>>(
313 &propertyPair.second);
314 if (domainNames != nullptr)
315 {
316 ethData.domainnames = std::move(*domainNames);
317 }
318 }
Ed Tanous029573d2019-02-01 10:57:49 -0800319 }
320 }
321 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700322
323 if (objpath.first == "/xyz/openbmc_project/network/config/dhcp")
324 {
325 if (ifacePair.first ==
326 "xyz.openbmc_project.Network.DHCPConfiguration")
327 {
328 for (const auto &propertyPair : ifacePair.second)
329 {
330 if (propertyPair.first == "DNSEnabled")
331 {
332 const bool *DNSEnabled =
333 std::get_if<bool>(&propertyPair.second);
334 if (DNSEnabled != nullptr)
335 {
336 ethData.DNSEnabled = *DNSEnabled;
337 }
338 }
339 else if (propertyPair.first == "NTPEnabled")
340 {
341 const bool *NTPEnabled =
342 std::get_if<bool>(&propertyPair.second);
343 if (NTPEnabled != nullptr)
344 {
345 ethData.NTPEnabled = *NTPEnabled;
346 }
347 }
348 else if (propertyPair.first == "HostNameEnabled")
349 {
350 const bool *HostNameEnabled =
351 std::get_if<bool>(&propertyPair.second);
352 if (HostNameEnabled != nullptr)
353 {
354 ethData.HostNameEnabled = *HostNameEnabled;
355 }
356 }
357 else if (propertyPair.first == "SendHostNameEnabled")
358 {
359 const bool *SendHostNameEnabled =
360 std::get_if<bool>(&propertyPair.second);
361 if (SendHostNameEnabled != nullptr)
362 {
363 ethData.SendHostNameEnabled =
364 *SendHostNameEnabled;
365 }
366 }
367 }
368 }
369 }
Ed Tanous029573d2019-02-01 10:57:49 -0800370 // System configuration shows up in the global namespace, so no need
371 // to check eth number
372 if (ifacePair.first ==
373 "xyz.openbmc_project.Network.SystemConfiguration")
374 {
375 for (const auto &propertyPair : ifacePair.second)
376 {
377 if (propertyPair.first == "HostName")
378 {
379 const std::string *hostname =
380 sdbusplus::message::variant_ns::get_if<std::string>(
381 &propertyPair.second);
382 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700383 {
Ed Tanous029573d2019-02-01 10:57:49 -0800384 ethData.hostname = *hostname;
385 }
386 }
387 else if (propertyPair.first == "DefaultGateway")
388 {
389 const std::string *defaultGateway =
390 sdbusplus::message::variant_ns::get_if<std::string>(
391 &propertyPair.second);
392 if (defaultGateway != nullptr)
393 {
394 ethData.default_gateway = *defaultGateway;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700395 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -0500397 else if (propertyPair.first == "DefaultGateway6")
398 {
399 const std::string *defaultGateway6 =
400 sdbusplus::message::variant_ns::get_if<std::string>(
401 &propertyPair.second);
402 if (defaultGateway6 != nullptr)
403 {
404 ethData.ipv6_default_gateway = *defaultGateway6;
405 }
406 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407 }
408 }
409 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700411 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700412}
413
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500414// Helper function that extracts data for single ethernet ipv6 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700415inline void
416 extractIPV6Data(const std::string &ethiface_id,
417 const GetManagedObjects &dbus_data,
418 boost::container::flat_set<IPv6AddressData> &ipv6_config)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500419{
420 const std::string ipv6PathStart =
421 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
422
423 // Since there might be several IPv6 configurations aligned with
424 // single ethernet interface, loop over all of them
425 for (const auto &objpath : dbus_data)
426 {
427 // Check if proper pattern for object path appears
428 if (boost::starts_with(objpath.first.str, ipv6PathStart))
429 {
430 for (auto &interface : objpath.second)
431 {
432 if (interface.first == "xyz.openbmc_project.Network.IP")
433 {
434 // Instance IPv6AddressData structure, and set as
435 // appropriate
436 std::pair<
437 boost::container::flat_set<IPv6AddressData>::iterator,
438 bool>
Ed Tanous271584a2019-07-09 16:24:22 -0700439 it = ipv6_config.insert(IPv6AddressData{});
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500440 IPv6AddressData &ipv6_address = *it.first;
Ed Tanous271584a2019-07-09 16:24:22 -0700441 ipv6_address.id =
442 objpath.first.str.substr(ipv6PathStart.size());
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500443 for (auto &property : interface.second)
444 {
445 if (property.first == "Address")
446 {
447 const std::string *address =
448 std::get_if<std::string>(&property.second);
449 if (address != nullptr)
450 {
451 ipv6_address.address = *address;
452 }
453 }
454 else if (property.first == "Origin")
455 {
456 const std::string *origin =
457 std::get_if<std::string>(&property.second);
458 if (origin != nullptr)
459 {
460 ipv6_address.origin =
461 translateAddressOriginDbusToRedfish(*origin,
462 false);
463 }
464 }
465 else if (property.first == "PrefixLength")
466 {
467 const uint8_t *prefix =
468 std::get_if<uint8_t>(&property.second);
469 if (prefix != nullptr)
470 {
471 ipv6_address.prefixLength = *prefix;
472 }
473 }
474 else
475 {
476 BMCWEB_LOG_ERROR
477 << "Got extra property: " << property.first
478 << " on the " << objpath.first.str << " object";
479 }
480 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500481 }
482 }
483 }
484 }
485}
486
Ed Tanous4a0cb852018-10-15 07:55:04 -0700487// Helper function that extracts data for single ethernet ipv4 address
Johnathan Mantey01784822019-06-18 12:44:21 -0700488inline void
489 extractIPData(const std::string &ethiface_id,
490 const GetManagedObjects &dbus_data,
491 boost::container::flat_set<IPv4AddressData> &ipv4_config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700492{
493 const std::string ipv4PathStart =
494 "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
495
496 // Since there might be several IPv4 configurations aligned with
497 // single ethernet interface, loop over all of them
498 for (const auto &objpath : dbus_data)
499 {
500 // Check if proper pattern for object path appears
501 if (boost::starts_with(objpath.first.str, ipv4PathStart))
502 {
503 for (auto &interface : objpath.second)
504 {
505 if (interface.first == "xyz.openbmc_project.Network.IP")
506 {
507 // Instance IPv4AddressData structure, and set as
508 // appropriate
509 std::pair<
510 boost::container::flat_set<IPv4AddressData>::iterator,
511 bool>
Ed Tanous271584a2019-07-09 16:24:22 -0700512 it = ipv4_config.insert(IPv4AddressData{});
Ed Tanous4a0cb852018-10-15 07:55:04 -0700513 IPv4AddressData &ipv4_address = *it.first;
Ed Tanous271584a2019-07-09 16:24:22 -0700514 ipv4_address.id =
515 objpath.first.str.substr(ipv4PathStart.size());
Ed Tanous4a0cb852018-10-15 07:55:04 -0700516 for (auto &property : interface.second)
517 {
518 if (property.first == "Address")
519 {
520 const std::string *address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800521 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700522 if (address != nullptr)
523 {
524 ipv4_address.address = *address;
525 }
526 }
527 else if (property.first == "Gateway")
528 {
529 const std::string *gateway =
Ed Tanousabf2add2019-01-22 16:40:12 -0800530 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700531 if (gateway != nullptr)
532 {
533 ipv4_address.gateway = *gateway;
534 }
535 }
536 else if (property.first == "Origin")
537 {
538 const std::string *origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800539 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700540 if (origin != nullptr)
541 {
542 ipv4_address.origin =
543 translateAddressOriginDbusToRedfish(*origin,
544 true);
545 }
546 }
547 else if (property.first == "PrefixLength")
548 {
549 const uint8_t *mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800550 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700551 if (mask != nullptr)
552 {
553 // convert it to the string
554 ipv4_address.netmask = getNetmask(*mask);
555 }
556 }
557 else
558 {
559 BMCWEB_LOG_ERROR
560 << "Got extra property: " << property.first
561 << " on the " << objpath.first.str << " object";
562 }
563 }
564 // Check if given address is local, or global
565 ipv4_address.linktype =
566 boost::starts_with(ipv4_address.address, "169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700567 ? LinkType::Local
568 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700569 }
570 }
571 }
572 }
573}
574
575/**
576 * @brief Sets given Id on the given VLAN interface through D-Bus
577 *
578 * @param[in] ifaceId Id of VLAN interface that should be modified
579 * @param[in] inputVlanId New ID of the VLAN
580 * @param[in] callback Function that will be called after the operation
581 *
582 * @return None.
583 */
584template <typename CallbackFunc>
585void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
586 CallbackFunc &&callback)
587{
588 crow::connections::systemBus->async_method_call(
589 callback, "xyz.openbmc_project.Network",
590 std::string("/xyz/openbmc_project/network/") + ifaceId,
591 "org.freedesktop.DBus.Properties", "Set",
592 "xyz.openbmc_project.Network.VLAN", "Id",
Ed Tanousabf2add2019-01-22 16:40:12 -0800593 std::variant<uint32_t>(inputVlanId));
Ed Tanous4a0cb852018-10-15 07:55:04 -0700594}
595
596/**
597 * @brief Helper function that verifies IP address to check if it is in
598 * proper format. If bits pointer is provided, also calculates active
599 * bit count for Subnet Mask.
600 *
601 * @param[in] ip IP that will be verified
602 * @param[out] bits Calculated mask in bits notation
603 *
604 * @return true in case of success, false otherwise
605 */
606inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
607 uint8_t *bits = nullptr)
608{
609 std::vector<std::string> bytesInMask;
610
611 boost::split(bytesInMask, ip, boost::is_any_of("."));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612
613 static const constexpr int ipV4AddressSectionsCount = 4;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700614 if (bytesInMask.size() != ipV4AddressSectionsCount)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700616 return false;
617 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618
Ed Tanous4a0cb852018-10-15 07:55:04 -0700619 if (bits != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700621 *bits = 0;
622 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623
Ed Tanous4a0cb852018-10-15 07:55:04 -0700624 char *endPtr;
625 long previousValue = 255;
626 bool firstZeroInByteHit;
627 for (const std::string &byte : bytesInMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700629 if (byte.empty())
630 {
631 return false;
632 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633
Ed Tanous4a0cb852018-10-15 07:55:04 -0700634 // Use strtol instead of stroi to avoid exceptions
635 long value = std::strtol(byte.c_str(), &endPtr, 10);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636
Ed Tanous4a0cb852018-10-15 07:55:04 -0700637 // endPtr should point to the end of the string, otherwise given string
638 // is not 100% number
639 if (*endPtr != '\0')
640 {
641 return false;
642 }
643
644 // Value should be contained in byte
645 if (value < 0 || value > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 {
647 return false;
648 }
649
650 if (bits != nullptr)
651 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700652 // Mask has to be continuous between bytes
653 if (previousValue != 255 && value != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
655 return false;
656 }
657
Ed Tanous4a0cb852018-10-15 07:55:04 -0700658 // Mask has to be continuous inside bytes
659 firstZeroInByteHit = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660
Ed Tanous4a0cb852018-10-15 07:55:04 -0700661 // Count bits
662 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700664 if (value & (1 << bitIdx))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700666 if (firstZeroInByteHit)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700668 // Continuity not preserved
669 return false;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 }
671 else
672 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700673 (*bits)++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 }
675 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 else
677 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700678 firstZeroInByteHit = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700680 }
681 }
682
683 previousValue = value;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 }
685
Ed Tanous4a0cb852018-10-15 07:55:04 -0700686 return true;
687}
688
689/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700690 * @brief Deletes given IPv4 interface
Ed Tanous4a0cb852018-10-15 07:55:04 -0700691 *
692 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700693 * @param[in] ipHash DBus Hash id of IP that should be deleted
694 * @param[io] asyncResp Response object that will be returned to client
695 *
696 * @return None
697 */
698inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700699 const std::shared_ptr<AsyncResp> asyncResp)
700{
701 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700702 [asyncResp](const boost::system::error_code ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 if (ec)
704 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -0800705 messages::internalError(asyncResp->res);
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100706 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700707 },
708 "xyz.openbmc_project.Network",
709 "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
710 "xyz.openbmc_project.Object.Delete", "Delete");
711}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712
Ed Tanous4a0cb852018-10-15 07:55:04 -0700713/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700714 * @brief Creates a static IPv4 entry
Ed Tanous4a0cb852018-10-15 07:55:04 -0700715 *
Johnathan Mantey01784822019-06-18 12:44:21 -0700716 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
717 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
718 * @param[in] gateway IPv4 address of this interfaces gateway
719 * @param[in] address IPv4 address to assign to this interface
720 * @param[io] asyncResp Response object that will be returned to client
Ed Tanous4a0cb852018-10-15 07:55:04 -0700721 *
722 * @return None
723 */
Ed Tanousb01bf292019-03-25 19:25:26 +0000724inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
Johnathan Mantey01784822019-06-18 12:44:21 -0700725 uint8_t prefixLength, const std::string &gateway,
Ed Tanousb01bf292019-03-25 19:25:26 +0000726 const std::string &address,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700727 std::shared_ptr<AsyncResp> asyncResp)
728{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700729 crow::connections::systemBus->async_method_call(
Johnathan Mantey01784822019-06-18 12:44:21 -0700730 [asyncResp](const boost::system::error_code ec) {
731 if (ec)
732 {
733 messages::internalError(asyncResp->res);
734 }
735 },
736 "xyz.openbmc_project.Network",
Ed Tanous4a0cb852018-10-15 07:55:04 -0700737 "/xyz/openbmc_project/network/" + ifaceId,
738 "xyz.openbmc_project.Network.IP.Create", "IP",
Johnathan Mantey01784822019-06-18 12:44:21 -0700739 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, prefixLength,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700740 gateway);
741}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500742
743/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700744 * @brief Deletes the IPv4 entry for this interface and creates a replacement
745 * static IPv4 entry
746 *
747 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
748 * @param[in] id The unique hash entry identifying the DBus entry
749 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
750 * @param[in] gateway IPv4 address of this interfaces gateway
751 * @param[in] address IPv4 address to assign to this interface
752 * @param[io] asyncResp Response object that will be returned to client
753 *
754 * @return None
755 */
756inline void deleteAndCreateIPv4(const std::string &ifaceId,
757 const std::string &id, uint8_t prefixLength,
758 const std::string &gateway,
759 const std::string &address,
760 std::shared_ptr<AsyncResp> asyncResp)
761{
762 crow::connections::systemBus->async_method_call(
763 [asyncResp, ifaceId, address, prefixLength,
764 gateway](const boost::system::error_code ec) {
765 if (ec)
766 {
767 messages::internalError(asyncResp->res);
768 }
769 crow::connections::systemBus->async_method_call(
770 [asyncResp](const boost::system::error_code ec) {
771 if (ec)
772 {
773 messages::internalError(asyncResp->res);
774 }
775 },
776 "xyz.openbmc_project.Network",
777 "/xyz/openbmc_project/network/" + ifaceId,
778 "xyz.openbmc_project.Network.IP.Create", "IP",
779 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address,
780 prefixLength, gateway);
781 },
782 "xyz.openbmc_project.Network",
783 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + id,
784 "xyz.openbmc_project.Object.Delete", "Delete");
785}
786
787/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500788 * @brief Deletes given IPv6
789 *
790 * @param[in] ifaceId Id of interface whose IP should be deleted
791 * @param[in] ipHash DBus Hash id of IP that should be deleted
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500792 * @param[io] asyncResp Response object that will be returned to client
793 *
794 * @return None
795 */
796inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500797 const std::shared_ptr<AsyncResp> asyncResp)
798{
799 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -0700800 [asyncResp](const boost::system::error_code ec) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500801 if (ec)
802 {
803 messages::internalError(asyncResp->res);
804 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500805 },
806 "xyz.openbmc_project.Network",
807 "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
808 "xyz.openbmc_project.Object.Delete", "Delete");
809}
810
811/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700812 * @brief Deletes the IPv6 entry for this interface and creates a replacement
813 * static IPv6 entry
814 *
815 * @param[in] ifaceId Id of interface upon which to create the IPv6 entry
816 * @param[in] id The unique hash entry identifying the DBus entry
817 * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
818 * @param[in] address IPv6 address to assign to this interface
819 * @param[io] asyncResp Response object that will be returned to client
820 *
821 * @return None
822 */
823inline void deleteAndCreateIPv6(const std::string &ifaceId,
824 const std::string &id, uint8_t prefixLength,
825 const std::string &address,
826 std::shared_ptr<AsyncResp> asyncResp)
827{
828 crow::connections::systemBus->async_method_call(
829 [asyncResp, ifaceId, address,
830 prefixLength](const boost::system::error_code ec) {
831 if (ec)
832 {
833 messages::internalError(asyncResp->res);
834 }
835 crow::connections::systemBus->async_method_call(
836 [asyncResp](const boost::system::error_code ec) {
837 if (ec)
838 {
839 messages::internalError(asyncResp->res);
840 }
841 },
842 "xyz.openbmc_project.Network",
843 "/xyz/openbmc_project/network/" + ifaceId,
844 "xyz.openbmc_project.Network.IP.Create", "IP",
845 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address,
846 prefixLength, "");
847 },
848 "xyz.openbmc_project.Network",
849 +"/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + id,
850 "xyz.openbmc_project.Object.Delete", "Delete");
851}
852
853/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500854 * @brief Creates IPv6 with given data
855 *
856 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500857 * @param[in] prefixLength Prefix length that needs to be added
858 * @param[in] address IP address that needs to be added
859 * @param[io] asyncResp Response object that will be returned to client
860 *
861 * @return None
862 */
Johnathan Mantey01784822019-06-18 12:44:21 -0700863inline void createIPv6(const std::string &ifaceId, uint8_t prefixLength,
864 const std::string &address,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500865 std::shared_ptr<AsyncResp> asyncResp)
866{
867 auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
868 if (ec)
869 {
870 messages::internalError(asyncResp->res);
871 }
872 };
873 // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
874 // does not have assosiated gateway property
875 crow::connections::systemBus->async_method_call(
876 std::move(createIpHandler), "xyz.openbmc_project.Network",
877 "/xyz/openbmc_project/network/" + ifaceId,
878 "xyz.openbmc_project.Network.IP.Create", "IP",
879 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
880 "");
881}
882
Ed Tanous4a0cb852018-10-15 07:55:04 -0700883/**
884 * Function that retrieves all properties for given Ethernet Interface
885 * Object
886 * from EntityManager Network Manager
887 * @param ethiface_id a eth interface id to query on DBus
888 * @param callback a function that shall be called to convert Dbus output
889 * into JSON
890 */
891template <typename CallbackFunc>
892void getEthernetIfaceData(const std::string &ethiface_id,
893 CallbackFunc &&callback)
894{
895 crow::connections::systemBus->async_method_call(
896 [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
897 const boost::system::error_code error_code,
898 const GetManagedObjects &resp) {
899 EthernetInterfaceData ethData{};
900 boost::container::flat_set<IPv4AddressData> ipv4Data;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500901 boost::container::flat_set<IPv6AddressData> ipv6Data;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700902
903 if (error_code)
904 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700905 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700906 return;
907 }
908
Ed Tanous4c9afe42019-05-03 16:59:57 -0700909 bool found =
910 extractEthernetInterfaceData(ethiface_id, resp, ethData);
911 if (!found)
912 {
Johnathan Mantey01784822019-06-18 12:44:21 -0700913 callback(false, ethData, ipv4Data, ipv6Data);
Ed Tanous4c9afe42019-05-03 16:59:57 -0700914 return;
915 }
916
Johnathan Mantey01784822019-06-18 12:44:21 -0700917 extractIPData(ethiface_id, resp, ipv4Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700918 // Fix global GW
919 for (IPv4AddressData &ipv4 : ipv4Data)
920 {
Ravi Tejac6191412019-07-30 00:53:50 -0500921 if (((ipv4.linktype == LinkType::Global) &&
922 (ipv4.gateway == "0.0.0.0")) ||
923 (ipv4.origin == "DHCP"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700925 ipv4.gateway = ethData.default_gateway;
926 }
927 }
928
Johnathan Mantey01784822019-06-18 12:44:21 -0700929 extractIPV6Data(ethiface_id, resp, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700930 // Finally make a callback with usefull data
Johnathan Mantey01784822019-06-18 12:44:21 -0700931 callback(true, ethData, ipv4Data, ipv6Data);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700932 },
933 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
934 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous271584a2019-07-09 16:24:22 -0700935}
Ed Tanous4a0cb852018-10-15 07:55:04 -0700936
937/**
938 * Function that retrieves all Ethernet Interfaces available through Network
939 * Manager
940 * @param callback a function that shall be called to convert Dbus output
941 * into JSON.
942 */
943template <typename CallbackFunc>
944void getEthernetIfaceList(CallbackFunc &&callback)
945{
946 crow::connections::systemBus->async_method_call(
947 [callback{std::move(callback)}](
948 const boost::system::error_code error_code,
949 GetManagedObjects &resp) {
950 // Callback requires vector<string> to retrieve all available
951 // ethernet interfaces
Ed Tanous4c9afe42019-05-03 16:59:57 -0700952 boost::container::flat_set<std::string> iface_list;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700953 iface_list.reserve(resp.size());
954 if (error_code)
955 {
956 callback(false, iface_list);
957 return;
958 }
959
960 // Iterate over all retrieved ObjectPaths.
961 for (const auto &objpath : resp)
962 {
963 // And all interfaces available for certain ObjectPath.
964 for (const auto &interface : objpath.second)
965 {
966 // If interface is
967 // xyz.openbmc_project.Network.EthernetInterface, this is
968 // what we're looking for.
969 if (interface.first ==
970 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700971 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700972 // Cut out everyting until last "/", ...
973 const std::string &iface_id = objpath.first.str;
974 std::size_t last_pos = iface_id.rfind("/");
975 if (last_pos != std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700976 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700977 // and put it into output vector.
Ed Tanous4c9afe42019-05-03 16:59:57 -0700978 iface_list.emplace(iface_id.substr(last_pos + 1));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700979 }
980 }
981 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700982 }
983 // Finally make a callback with useful data
984 callback(true, iface_list);
985 },
986 "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
987 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Ed Tanous271584a2019-07-09 16:24:22 -0700988}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100989
990/**
991 * EthernetCollection derived class for delivering Ethernet Collection Schema
992 */
Ed Tanous1abe55e2018-09-05 08:30:59 -0700993class EthernetCollection : public Node
994{
995 public:
Ed Tanous4a0cb852018-10-15 07:55:04 -0700996 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 EthernetCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -0700998 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700999 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001000 entityPrivileges = {
1001 {boost::beast::http::verb::get, {{"Login"}}},
1002 {boost::beast::http::verb::head, {{"Login"}}},
1003 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1004 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1005 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1006 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1007 }
1008
1009 private:
1010 /**
1011 * Functions triggers appropriate requests on DBus
1012 */
1013 void doGet(crow::Response &res, const crow::Request &req,
1014 const std::vector<std::string> &params) override
1015 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001016 res.jsonValue["@odata.type"] =
1017 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08001018 res.jsonValue["@odata.id"] =
1019 "/redfish/v1/Managers/bmc/EthernetInterfaces";
1020 res.jsonValue["Name"] = "Ethernet Network Interface Collection";
1021 res.jsonValue["Description"] =
1022 "Collection of EthernetInterfaces for this Manager";
Ed Tanous4c9afe42019-05-03 16:59:57 -07001023 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001024 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07001026 getEthernetIfaceList(
Ed Tanous4c9afe42019-05-03 16:59:57 -07001027 [asyncResp](
1028 const bool &success,
1029 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001030 if (!success)
1031 {
Ed Tanous4c9afe42019-05-03 16:59:57 -07001032 messages::internalError(asyncResp->res);
Jason M. Billsf12894f2018-10-09 12:45:45 -07001033 return;
1034 }
1035
Ed Tanous4c9afe42019-05-03 16:59:57 -07001036 nlohmann::json &iface_array =
1037 asyncResp->res.jsonValue["Members"];
Jason M. Billsf12894f2018-10-09 12:45:45 -07001038 iface_array = nlohmann::json::array();
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001039 std::string tag = "_";
Jason M. Billsf12894f2018-10-09 12:45:45 -07001040 for (const std::string &iface_item : iface_list)
1041 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001042 std::size_t found = iface_item.find(tag);
1043 if (found == std::string::npos)
1044 {
1045 iface_array.push_back(
1046 {{"@odata.id",
1047 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1048 iface_item}});
1049 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07001050 }
1051
Ed Tanous4c9afe42019-05-03 16:59:57 -07001052 asyncResp->res.jsonValue["Members@odata.count"] =
1053 iface_array.size();
1054 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsf12894f2018-10-09 12:45:45 -07001055 "/redfish/v1/Managers/bmc/EthernetInterfaces";
Jason M. Billsf12894f2018-10-09 12:45:45 -07001056 });
Ed Tanous4a0cb852018-10-15 07:55:04 -07001057 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001058};
1059
1060/**
1061 * EthernetInterface derived class for delivering Ethernet Schema
1062 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001063class EthernetInterface : public Node
1064{
1065 public:
1066 /*
1067 * Default Constructor
1068 */
Ed Tanous4a0cb852018-10-15 07:55:04 -07001069 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001070 EthernetInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001071 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
Ed Tanous1abe55e2018-09-05 08:30:59 -07001072 std::string())
1073 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001074 entityPrivileges = {
1075 {boost::beast::http::verb::get, {{"Login"}}},
1076 {boost::beast::http::verb::head, {{"Login"}}},
1077 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1078 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1079 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1080 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamil588c3f02018-04-03 14:55:27 +02001081 }
1082
Ed Tanous1abe55e2018-09-05 08:30:59 -07001083 private:
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001084 void handleHostnamePatch(const std::string &hostname,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001085 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001086 {
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001087 asyncResp->res.jsonValue["HostName"] = hostname;
1088 crow::connections::systemBus->async_method_call(
1089 [asyncResp](const boost::system::error_code ec) {
1090 if (ec)
1091 {
1092 messages::internalError(asyncResp->res);
1093 }
1094 },
1095 "xyz.openbmc_project.Network",
1096 "/xyz/openbmc_project/network/config",
1097 "org.freedesktop.DBus.Properties", "Set",
1098 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ed Tanousabf2add2019-01-22 16:40:12 -08001099 std::variant<std::string>(hostname));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001100 }
1101
Ratan Guptad5776652019-03-03 08:47:22 +05301102 void handleMACAddressPatch(const std::string &ifaceId,
1103 const std::string &macAddress,
1104 const std::shared_ptr<AsyncResp> &asyncResp)
1105 {
1106 crow::connections::systemBus->async_method_call(
1107 [asyncResp, macAddress](const boost::system::error_code ec) {
1108 if (ec)
1109 {
1110 messages::internalError(asyncResp->res);
1111 return;
1112 }
Ratan Guptad5776652019-03-03 08:47:22 +05301113 },
1114 "xyz.openbmc_project.Network",
1115 "/xyz/openbmc_project/network/" + ifaceId,
1116 "org.freedesktop.DBus.Properties", "Set",
1117 "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1118 std::variant<std::string>(macAddress));
1119 }
Johnathan Mantey286b9112019-06-10 13:38:04 -07001120
Jennifer Leeda131a92019-04-24 15:13:55 -07001121 void setDHCPEnabled(const std::string &ifaceId,
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001122 const std::string &propertyName, const bool v4Value,
1123 const bool v6Value,
Jennifer Leeda131a92019-04-24 15:13:55 -07001124 const std::shared_ptr<AsyncResp> asyncResp)
1125 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001126 const std::string dhcp = GetDHCPEnabledEnumeration(v4Value, v6Value);
Jennifer Leeda131a92019-04-24 15:13:55 -07001127 crow::connections::systemBus->async_method_call(
1128 [asyncResp](const boost::system::error_code ec) {
1129 if (ec)
1130 {
1131 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1132 messages::internalError(asyncResp->res);
1133 return;
1134 }
1135 },
1136 "xyz.openbmc_project.Network",
1137 "/xyz/openbmc_project/network/" + ifaceId,
1138 "org.freedesktop.DBus.Properties", "Set",
1139 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001140 std::variant<std::string>{dhcp});
Jennifer Leeda131a92019-04-24 15:13:55 -07001141 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001142
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001143 void setEthernetInterfaceBoolProperty(
1144 const std::string &ifaceId, const std::string &propertyName,
1145 const bool &value, const std::shared_ptr<AsyncResp> asyncResp)
1146 {
1147 crow::connections::systemBus->async_method_call(
1148 [asyncResp](const boost::system::error_code ec) {
1149 if (ec)
1150 {
1151 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1152 messages::internalError(asyncResp->res);
1153 return;
1154 }
1155 },
1156 "xyz.openbmc_project.Network",
1157 "/xyz/openbmc_project/network/" + ifaceId,
1158 "org.freedesktop.DBus.Properties", "Set",
1159 "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1160 std::variant<bool>{value});
1161 }
1162
Jennifer Leeda131a92019-04-24 15:13:55 -07001163 void setDHCPv4Config(const std::string &propertyName, const bool &value,
1164 const std::shared_ptr<AsyncResp> asyncResp)
1165 {
1166 BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1167 crow::connections::systemBus->async_method_call(
1168 [asyncResp](const boost::system::error_code ec) {
1169 if (ec)
1170 {
1171 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1172 messages::internalError(asyncResp->res);
1173 return;
1174 }
1175 },
1176 "xyz.openbmc_project.Network",
1177 "/xyz/openbmc_project/network/config/dhcp",
1178 "org.freedesktop.DBus.Properties", "Set",
1179 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1180 std::variant<bool>{value});
1181 }
Ratan Guptad5776652019-03-03 08:47:22 +05301182
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001183 void handleDHCPPatch(const std::string &ifaceId,
1184 const EthernetInterfaceData &ethData,
1185 DHCPParameters v4dhcpParms, DHCPParameters v6dhcpParms,
1186 const std::shared_ptr<AsyncResp> asyncResp)
Jennifer Leeda131a92019-04-24 15:13:55 -07001187 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001188 bool ipv4Active = translateDHCPEnabledToBool(ethData.DHCPEnabled, true);
1189 bool ipv6Active =
1190 translateDHCPEnabledToBool(ethData.DHCPEnabled, false);
Jennifer Leeda131a92019-04-24 15:13:55 -07001191
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001192 bool nextv4DHCPState =
1193 v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active;
1194
1195 bool nextv6DHCPState{};
1196 if (v6dhcpParms.dhcpv6OperatingMode)
Jennifer Leeda131a92019-04-24 15:13:55 -07001197 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001198 if ((*v6dhcpParms.dhcpv6OperatingMode != "Stateful") &&
1199 (*v6dhcpParms.dhcpv6OperatingMode != "Stateless") &&
1200 (*v6dhcpParms.dhcpv6OperatingMode != "Disabled"))
1201 {
1202 messages::propertyValueFormatError(
1203 asyncResp->res, *v6dhcpParms.dhcpv6OperatingMode,
1204 "OperatingMode");
1205 return;
1206 }
1207 nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Stateful");
1208 }
1209 else
1210 {
1211 nextv6DHCPState = ipv6Active;
Jennifer Leeda131a92019-04-24 15:13:55 -07001212 }
1213
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001214 bool nextDNS{};
1215 if (v4dhcpParms.useDNSServers && v6dhcpParms.useDNSServers)
Jennifer Leeda131a92019-04-24 15:13:55 -07001216 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001217 if (*v4dhcpParms.useDNSServers != *v6dhcpParms.useDNSServers)
1218 {
1219 messages::generalError(asyncResp->res);
1220 return;
1221 }
1222 nextDNS = *v4dhcpParms.useDNSServers;
1223 }
1224 else if (v4dhcpParms.useDNSServers)
1225 {
1226 nextDNS = *v4dhcpParms.useDNSServers;
1227 }
1228 else if (v6dhcpParms.useDNSServers)
1229 {
1230 nextDNS = *v6dhcpParms.useDNSServers;
1231 }
1232 else
1233 {
1234 nextDNS = ethData.DNSEnabled;
Jennifer Leeda131a92019-04-24 15:13:55 -07001235 }
1236
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001237 bool nextNTP{};
1238 if (v4dhcpParms.useNTPServers && v6dhcpParms.useNTPServers)
Jennifer Leeda131a92019-04-24 15:13:55 -07001239 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001240 if (*v4dhcpParms.useNTPServers != *v6dhcpParms.useNTPServers)
1241 {
1242 messages::generalError(asyncResp->res);
1243 return;
1244 }
1245 nextNTP = *v4dhcpParms.useNTPServers;
1246 }
1247 else if (v4dhcpParms.useNTPServers)
1248 {
1249 nextNTP = *v4dhcpParms.useNTPServers;
1250 }
1251 else if (v6dhcpParms.useNTPServers)
1252 {
1253 nextNTP = *v6dhcpParms.useNTPServers;
1254 }
1255 else
1256 {
1257 nextNTP = ethData.NTPEnabled;
Jennifer Leeda131a92019-04-24 15:13:55 -07001258 }
1259
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001260 bool nextUseDomain{};
1261 if (v4dhcpParms.useUseDomainName && v6dhcpParms.useUseDomainName)
Jennifer Leeda131a92019-04-24 15:13:55 -07001262 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001263 if (*v4dhcpParms.useUseDomainName != *v6dhcpParms.useUseDomainName)
1264 {
1265 messages::generalError(asyncResp->res);
1266 return;
1267 }
1268 nextUseDomain = *v4dhcpParms.useUseDomainName;
1269 }
1270 else if (v4dhcpParms.useUseDomainName)
1271 {
1272 nextUseDomain = *v4dhcpParms.useUseDomainName;
1273 }
1274 else if (v6dhcpParms.useUseDomainName)
1275 {
1276 nextUseDomain = *v6dhcpParms.useUseDomainName;
1277 }
1278 else
1279 {
1280 nextUseDomain = ethData.HostNameEnabled;
Jennifer Leeda131a92019-04-24 15:13:55 -07001281 }
1282
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001283 BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1284 setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState,
1285 asyncResp);
1286 BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1287 setDHCPv4Config("DNSEnabled", nextDNS, asyncResp);
1288 BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1289 setDHCPv4Config("NTPEnabled", nextNTP, asyncResp);
1290 BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1291 setDHCPv4Config("HostNameEnabled", nextUseDomain, asyncResp);
Jennifer Leeda131a92019-04-24 15:13:55 -07001292 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001293
1294 boost::container::flat_set<IPv4AddressData>::const_iterator
1295 GetNextStaticIPEntry(
1296 boost::container::flat_set<IPv4AddressData>::const_iterator head,
1297 boost::container::flat_set<IPv4AddressData>::const_iterator end)
1298 {
1299 for (; head != end; head++)
1300 {
1301 if (head->origin == "Static")
1302 {
1303 return head;
1304 }
1305 }
1306 return end;
1307 }
1308
1309 boost::container::flat_set<IPv6AddressData>::const_iterator
1310 GetNextStaticIPEntry(
1311 boost::container::flat_set<IPv6AddressData>::const_iterator head,
1312 boost::container::flat_set<IPv6AddressData>::const_iterator end)
1313 {
1314 for (; head != end; head++)
1315 {
1316 if (head->origin == "Static")
1317 {
1318 return head;
1319 }
1320 }
1321 return end;
1322 }
1323
Ravi Tejad1d50812019-06-23 16:20:27 -05001324 void handleIPv4StaticPatch(
Ratan Guptaf476acb2019-03-02 16:46:57 +05301325 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001326 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Ed Tanous4a0cb852018-10-15 07:55:04 -07001327 const std::shared_ptr<AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001328 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001329 if ((!input.is_array()) || input.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301330 {
1331 messages::propertyValueTypeError(asyncResp->res, input.dump(),
Ravi Tejad1d50812019-06-23 16:20:27 -05001332 "IPv4StaticAddresses");
Ratan Guptaf476acb2019-03-02 16:46:57 +05301333 return;
1334 }
1335
Ed Tanous271584a2019-07-09 16:24:22 -07001336 unsigned entryIdx = 1;
Johnathan Mantey01784822019-06-18 12:44:21 -07001337 // Find the first static IP address currently active on the NIC and
1338 // match it to the first JSON element in the IPv4StaticAddresses array.
1339 // Match each subsequent JSON element to the next static IP programmed
1340 // into the NIC.
1341 boost::container::flat_set<IPv4AddressData>::const_iterator NICIPentry =
1342 GetNextStaticIPEntry(ipv4Data.cbegin(), ipv4Data.cend());
1343
Ed Tanous537174c2018-12-10 15:09:31 -08001344 for (nlohmann::json &thisJson : input)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001346 std::string pathString =
Ravi Tejad1d50812019-06-23 16:20:27 -05001347 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348
Johnathan Mantey01784822019-06-18 12:44:21 -07001349 if (!thisJson.is_null() && !thisJson.empty())
Ratan Guptaf476acb2019-03-02 16:46:57 +05301350 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001351 std::optional<std::string> address;
1352 std::optional<std::string> subnetMask;
1353 std::optional<std::string> gateway;
1354
1355 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1356 address, "SubnetMask", subnetMask,
1357 "Gateway", gateway))
Ratan Guptaf476acb2019-03-02 16:46:57 +05301358 {
1359 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001360 asyncResp->res, thisJson.dump(), pathString);
Ratan Guptaf476acb2019-03-02 16:46:57 +05301361 return;
Ratan Guptaf476acb2019-03-02 16:46:57 +05301362 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301363
Johnathan Mantey01784822019-06-18 12:44:21 -07001364 // Find the address/subnet/gateway values. Any values that are
1365 // not explicitly provided are assumed to be unmodified from the
1366 // current state of the interface. Merge existing state into the
1367 // current request.
Ed Tanous271584a2019-07-09 16:24:22 -07001368 const std::string *addr = nullptr;
1369 const std::string *gw = nullptr;
Johnathan Mantey01784822019-06-18 12:44:21 -07001370 uint8_t prefixLength = 0;
1371 bool errorInEntry = false;
1372 if (address)
Ratan Gupta9474b372019-03-01 15:13:37 +05301373 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001374 if (ipv4VerifyIpAndGetBitcount(*address))
1375 {
1376 addr = &(*address);
1377 }
1378 else
1379 {
1380 messages::propertyValueFormatError(
1381 asyncResp->res, *address, pathString + "/Address");
1382 errorInEntry = true;
1383 }
1384 }
1385 else if (NICIPentry != ipv4Data.cend())
1386 {
1387 addr = &(NICIPentry->address);
Ratan Gupta9474b372019-03-01 15:13:37 +05301388 }
1389 else
1390 {
1391 messages::propertyMissing(asyncResp->res,
1392 pathString + "/Address");
Johnathan Mantey01784822019-06-18 12:44:21 -07001393 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001394 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301395
1396 if (subnetMask)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001397 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001398 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
1399 {
1400 messages::propertyValueFormatError(
1401 asyncResp->res, *subnetMask,
1402 pathString + "/SubnetMask");
1403 errorInEntry = true;
1404 }
1405 }
1406 else if (NICIPentry != ipv4Data.cend())
1407 {
1408 if (!ipv4VerifyIpAndGetBitcount(NICIPentry->netmask,
1409 &prefixLength))
1410 {
1411 messages::propertyValueFormatError(
1412 asyncResp->res, NICIPentry->netmask,
1413 pathString + "/SubnetMask");
1414 errorInEntry = true;
1415 }
1416 }
1417 else
1418 {
1419 messages::propertyMissing(asyncResp->res,
1420 pathString + "/SubnetMask");
1421 errorInEntry = true;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301423
Ratan Guptaf476acb2019-03-02 16:46:57 +05301424 if (gateway)
1425 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001426 if (ipv4VerifyIpAndGetBitcount(*gateway))
1427 {
1428 gw = &(*gateway);
1429 }
1430 else
1431 {
1432 messages::propertyValueFormatError(
1433 asyncResp->res, *gateway, pathString + "/Gateway");
1434 errorInEntry = true;
1435 }
Ratan Guptaf476acb2019-03-02 16:46:57 +05301436 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001437 else if (NICIPentry != ipv4Data.cend())
1438 {
1439 gw = &NICIPentry->gateway;
1440 }
1441 else
Ed Tanous4a0cb852018-10-15 07:55:04 -07001442 {
Jason M. Billsa08b46c2018-11-06 15:01:08 -08001443 messages::propertyMissing(asyncResp->res,
Jason M. Billsf12894f2018-10-09 12:45:45 -07001444 pathString + "/Gateway");
Johnathan Mantey01784822019-06-18 12:44:21 -07001445 errorInEntry = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001446 }
1447
Johnathan Mantey01784822019-06-18 12:44:21 -07001448 if (errorInEntry)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001449 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001450 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001451 }
1452
Johnathan Mantey01784822019-06-18 12:44:21 -07001453 if (NICIPentry != ipv4Data.cend())
Ed Tanous4a0cb852018-10-15 07:55:04 -07001454 {
Ed Tanous271584a2019-07-09 16:24:22 -07001455 if (gw != nullptr || addr != nullptr)
1456 {
1457 // Shouldn't be possible based on errorInEntry, but
1458 // it flags -wmaybe-uninitialized in the compiler,
1459 // so defend against that
1460 return;
1461 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001462 deleteAndCreateIPv4(ifaceId, NICIPentry->id, prefixLength,
1463 *gw, *addr, asyncResp);
1464 NICIPentry =
1465 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
Ed Tanous4a0cb852018-10-15 07:55:04 -07001466 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001467 else
1468 {
1469 createIPv4(ifaceId, entryIdx, prefixLength, *gateway,
1470 *address, asyncResp);
1471 }
1472 entryIdx++;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001473 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001474 else
1475 {
1476 if (NICIPentry == ipv4Data.cend())
1477 {
1478 // Requesting a DELETE/DO NOT MODIFY action for an item
1479 // that isn't present on the eth(n) interface. Input JSON is
1480 // in error, so bail out.
1481 if (thisJson.is_null())
1482 {
1483 messages::resourceCannotBeDeleted(asyncResp->res);
1484 return;
1485 }
1486 else
1487 {
1488 messages::propertyValueFormatError(
1489 asyncResp->res, thisJson.dump(), pathString);
1490 return;
1491 }
1492 }
1493
1494 if (thisJson.is_null())
1495 {
1496 deleteIPv4(ifaceId, NICIPentry->id, asyncResp);
1497 }
1498 if (NICIPentry != ipv4Data.cend())
1499 {
1500 NICIPentry =
1501 GetNextStaticIPEntry(++NICIPentry, ipv4Data.cend());
1502 }
1503 entryIdx++;
1504 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001505 }
1506 }
1507
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001508 void handleStaticNameServersPatch(
1509 const std::string &ifaceId,
1510 const std::vector<std::string> &updatedStaticNameServers,
1511 const std::shared_ptr<AsyncResp> &asyncResp)
1512 {
1513 crow::connections::systemBus->async_method_call(
Johnathan Mantey286b9112019-06-10 13:38:04 -07001514 [asyncResp](const boost::system::error_code ec) {
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001515 if (ec)
1516 {
1517 messages::internalError(asyncResp->res);
1518 return;
1519 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001520 },
1521 "xyz.openbmc_project.Network",
1522 "/xyz/openbmc_project/network/" + ifaceId,
1523 "org.freedesktop.DBus.Properties", "Set",
1524 "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1525 std::variant<std::vector<std::string>>{updatedStaticNameServers});
1526 }
1527
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001528 void handleIPv6StaticAddressesPatch(
1529 const std::string &ifaceId, nlohmann::json &input,
Johnathan Mantey01784822019-06-18 12:44:21 -07001530 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001531 const std::shared_ptr<AsyncResp> asyncResp)
1532 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001533 if (!input.is_array() || input.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001534 {
1535 messages::propertyValueTypeError(asyncResp->res, input.dump(),
1536 "IPv6StaticAddresses");
1537 return;
1538 }
Ed Tanous271584a2019-07-09 16:24:22 -07001539 size_t entryIdx = 1;
Johnathan Mantey01784822019-06-18 12:44:21 -07001540 boost::container::flat_set<IPv6AddressData>::const_iterator NICIPentry =
1541 GetNextStaticIPEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001542 for (nlohmann::json &thisJson : input)
1543 {
1544 std::string pathString =
1545 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1546
Johnathan Mantey01784822019-06-18 12:44:21 -07001547 if (!thisJson.is_null() && !thisJson.empty())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001548 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001549 std::optional<std::string> address;
1550 std::optional<uint8_t> prefixLength;
1551
1552 if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1553 address, "PrefixLength", prefixLength))
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001554 {
1555 messages::propertyValueFormatError(
Johnathan Mantey01784822019-06-18 12:44:21 -07001556 asyncResp->res, thisJson.dump(), pathString);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001557 return;
1558 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001559
Johnathan Mantey01784822019-06-18 12:44:21 -07001560 const std::string *addr;
1561 uint8_t prefix;
1562
1563 // Find the address and prefixLength values. Any values that are
1564 // not explicitly provided are assumed to be unmodified from the
1565 // current state of the interface. Merge existing state into the
1566 // current request.
1567 if (address)
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001568 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001569 addr = &(*address);
1570 }
1571 else if (NICIPentry != ipv6Data.end())
1572 {
1573 addr = &(NICIPentry->address);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001574 }
1575 else
1576 {
1577 messages::propertyMissing(asyncResp->res,
1578 pathString + "/Address");
1579 return;
1580 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001581
1582 if (prefixLength)
1583 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001584 prefix = *prefixLength;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001585 }
Johnathan Mantey01784822019-06-18 12:44:21 -07001586 else if (NICIPentry != ipv6Data.end())
1587 {
1588 prefix = NICIPentry->prefixLength;
1589 }
1590 else
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001591 {
1592 messages::propertyMissing(asyncResp->res,
1593 pathString + "/PrefixLength");
Johnathan Mantey01784822019-06-18 12:44:21 -07001594 return;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001595 }
1596
Johnathan Mantey01784822019-06-18 12:44:21 -07001597 if (NICIPentry != ipv6Data.end())
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001598 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001599 deleteAndCreateIPv6(ifaceId, NICIPentry->id, prefix, *addr,
1600 asyncResp);
1601 NICIPentry =
1602 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1603 }
1604 else
1605 {
1606 createIPv6(ifaceId, *prefixLength, *addr, asyncResp);
1607 }
1608 entryIdx++;
1609 }
1610 else
1611 {
1612 if (NICIPentry == ipv6Data.end())
1613 {
1614 // Requesting a DELETE/DO NOT MODIFY action for an item
1615 // that isn't present on the eth(n) interface. Input JSON is
1616 // in error, so bail out.
1617 if (thisJson.is_null())
1618 {
1619 messages::resourceCannotBeDeleted(asyncResp->res);
1620 return;
1621 }
1622 else
1623 {
1624 messages::propertyValueFormatError(
1625 asyncResp->res, thisJson.dump(), pathString);
1626 return;
1627 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001628 }
1629
Johnathan Mantey01784822019-06-18 12:44:21 -07001630 if (thisJson.is_null())
1631 {
1632 deleteIPv6(ifaceId, NICIPentry->id, asyncResp);
1633 }
1634 if (NICIPentry != ipv6Data.cend())
1635 {
1636 NICIPentry =
1637 GetNextStaticIPEntry(++NICIPentry, ipv6Data.cend());
1638 }
1639 entryIdx++;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001640 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001641 }
1642 }
1643
Ed Tanous0f74e642018-11-12 15:17:05 -08001644 void parseInterfaceData(
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001645 std::shared_ptr<AsyncResp> asyncResp, const std::string &iface_id,
Ed Tanous0f74e642018-11-12 15:17:05 -08001646 const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001647 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001648 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649 {
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001650 constexpr const std::array<const char *, 1> inventoryForEthernet = {
1651 "xyz.openbmc_project.Inventory.Item.Ethernet"};
1652
1653 nlohmann::json &json_response = asyncResp->res.jsonValue;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001654 json_response["Id"] = iface_id;
1655 json_response["@odata.id"] =
1656 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001657 json_response["InterfaceEnabled"] = ethData.nicEnabled;
1658
1659 auto health = std::make_shared<HealthPopulate>(asyncResp);
1660
1661 crow::connections::systemBus->async_method_call(
1662 [health](const boost::system::error_code ec,
1663 std::vector<std::string> &resp) {
1664 if (ec)
1665 {
1666 return;
1667 }
1668
1669 health->inventory = std::move(resp);
1670 },
1671 "xyz.openbmc_project.ObjectMapper",
1672 "/xyz/openbmc_project/object_mapper",
1673 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1674 int32_t(0), inventoryForEthernet);
1675
1676 health->populate();
1677
1678 if (ethData.nicEnabled)
Ed Tanous029573d2019-02-01 10:57:49 -08001679 {
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001680 json_response["LinkStatus"] = "LinkUp";
1681 json_response["Status"]["State"] = "Enabled";
Ed Tanous029573d2019-02-01 10:57:49 -08001682 }
1683 else
1684 {
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001685 json_response["LinkStatus"] = "NoLink";
1686 json_response["Status"]["State"] = "Disabled";
Ed Tanous029573d2019-02-01 10:57:49 -08001687 }
Johnathan Manteyaa05fb22020-01-08 12:08:44 -08001688
1689 json_response["LinkStatus"] = ethData.linkUp ? "LinkUp" : "LinkDown";
Ed Tanous4a0cb852018-10-15 07:55:04 -07001690 json_response["SpeedMbps"] = ethData.speed;
1691 json_response["MACAddress"] = ethData.mac_address;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001692 json_response["DHCPv4"]["DHCPEnabled"] =
1693 translateDHCPEnabledToBool(ethData.DHCPEnabled, true);
1694 json_response["DHCPv4"]["UseNTPServers"] = ethData.NTPEnabled;
1695 json_response["DHCPv4"]["UseDNSServers"] = ethData.DNSEnabled;
1696 json_response["DHCPv4"]["UseDomainName"] = ethData.HostNameEnabled;
1697
1698 json_response["DHCPv6"]["OperatingMode"] =
1699 translateDHCPEnabledToBool(ethData.DHCPEnabled, false) ? "Stateful"
1700 : "Disabled";
1701 json_response["DHCPv6"]["UseNTPServers"] = ethData.NTPEnabled;
1702 json_response["DHCPv6"]["UseDNSServers"] = ethData.DNSEnabled;
1703 json_response["DHCPv6"]["UseDomainName"] = ethData.HostNameEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +05301704
Ed Tanous4a0cb852018-10-15 07:55:04 -07001705 if (!ethData.hostname.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001707 json_response["HostName"] = ethData.hostname;
Jennifer Leed24bfc72019-03-05 13:03:37 -08001708 if (!ethData.domainnames.empty())
1709 {
1710 json_response["FQDN"] =
1711 ethData.hostname + "." + ethData.domainnames[0];
1712 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001713 }
1714
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001715 json_response["VLANs"] = {
1716 {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1717 iface_id + "/VLANs"}};
1718
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001719 if (translateDHCPEnabledToBool(ethData.DHCPEnabled, true) &&
1720 ethData.DNSEnabled)
Manojkiran Eda95f86462019-08-07 15:07:54 +05301721 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001722 json_response["StaticNameServers"] = nlohmann::json::array();
Manojkiran Eda95f86462019-08-07 15:07:54 +05301723 }
1724 else
1725 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001726 json_response["StaticNameServers"] = ethData.nameservers;
Manojkiran Eda95f86462019-08-07 15:07:54 +05301727 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728
Ravi Tejad1d50812019-06-23 16:20:27 -05001729 nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001730 nlohmann::json &ipv4_static_array =
1731 json_response["IPv4StaticAddresses"];
Ravi Tejad1d50812019-06-23 16:20:27 -05001732 ipv4_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001733 ipv4_static_array = nlohmann::json::array();
Ravi Tejad1d50812019-06-23 16:20:27 -05001734 for (auto &ipv4_config : ipv4Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001736
1737 std::string gatewayStr = ipv4_config.gateway;
1738 if (gatewayStr.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001739 {
Ravi Tejad1d50812019-06-23 16:20:27 -05001740 gatewayStr = "0.0.0.0";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001742
1743 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1744 {"SubnetMask", ipv4_config.netmask},
1745 {"Address", ipv4_config.address},
1746 {"Gateway", gatewayStr}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001747 if (ipv4_config.origin == "Static")
Ravi Tejad1d50812019-06-23 16:20:27 -05001748 {
Johnathan Mantey01784822019-06-18 12:44:21 -07001749 ipv4_static_array.push_back(
1750 {{"AddressOrigin", ipv4_config.origin},
1751 {"SubnetMask", ipv4_config.netmask},
1752 {"Address", ipv4_config.address},
1753 {"Gateway", gatewayStr}});
Ravi Tejad1d50812019-06-23 16:20:27 -05001754 }
Ravi Tejad1d50812019-06-23 16:20:27 -05001755 }
1756
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001757 json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001758
1759 nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
Johnathan Mantey01784822019-06-18 12:44:21 -07001760 nlohmann::json &ipv6_static_array =
1761 json_response["IPv6StaticAddresses"];
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001762 ipv6_array = nlohmann::json::array();
Johnathan Mantey01784822019-06-18 12:44:21 -07001763 ipv6_static_array = nlohmann::json::array();
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001764 for (auto &ipv6_config : ipv6Data)
1765 {
1766 ipv6_array.push_back({{"Address", ipv6_config.address},
1767 {"PrefixLength", ipv6_config.prefixLength},
1768 {"AddressOrigin", ipv6_config.origin}});
Johnathan Mantey01784822019-06-18 12:44:21 -07001769 if (ipv6_config.origin == "Static")
1770 {
1771 ipv6_static_array.push_back(
1772 {{"Address", ipv6_config.address},
1773 {"PrefixLength", ipv6_config.prefixLength},
1774 {"AddressOrigin", ipv6_config.origin}});
1775 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001776 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001777 }
1778
1779 /**
1780 * Functions triggers appropriate requests on DBus
1781 */
1782 void doGet(crow::Response &res, const crow::Request &req,
1783 const std::vector<std::string> &params) override
1784 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001785 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001786 if (params.size() != 1)
1787 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001788 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001789 return;
1790 }
1791
Ed Tanous4a0cb852018-10-15 07:55:04 -07001792 getEthernetIfaceData(
1793 params[0],
1794 [this, asyncResp, iface_id{std::string(params[0])}](
1795 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001796 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001797 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001798 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001799 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001800 // TODO(Pawel)consider distinguish between non existing
1801 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07001802 messages::resourceNotFound(asyncResp->res,
1803 "EthernetInterface", iface_id);
Ed Tanous4a0cb852018-10-15 07:55:04 -07001804 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07001806
Ed Tanous0f74e642018-11-12 15:17:05 -08001807 asyncResp->res.jsonValue["@odata.type"] =
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001808 "#EthernetInterface.v1_4_1.EthernetInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08001809 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
1810 asyncResp->res.jsonValue["Description"] =
1811 "Management Network Interface";
1812
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001813 parseInterfaceData(asyncResp, iface_id, ethData, ipv4Data,
1814 ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001815 });
1816 }
1817
1818 void doPatch(crow::Response &res, const crow::Request &req,
1819 const std::vector<std::string> &params) override
1820 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07001821 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001822 if (params.size() != 1)
1823 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001824 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 return;
1826 }
1827
Ed Tanous4a0cb852018-10-15 07:55:04 -07001828 const std::string &iface_id = params[0];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001829
Ed Tanousbc0bd6e2018-12-10 14:07:55 -08001830 std::optional<std::string> hostname;
Ratan Guptad5776652019-03-03 08:47:22 +05301831 std::optional<std::string> macAddress;
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001832 std::optional<std::string> ipv6DefaultGateway;
Ravi Tejad1d50812019-06-23 16:20:27 -05001833 std::optional<nlohmann::json> ipv4StaticAddresses;
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001834 std::optional<nlohmann::json> ipv6StaticAddresses;
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001835 std::optional<std::vector<std::string>> staticNameServers;
Jennifer Leeda131a92019-04-24 15:13:55 -07001836 std::optional<nlohmann::json> dhcpv4;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001837 std::optional<nlohmann::json> dhcpv6;
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001838 std::optional<bool> interfaceEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001839 DHCPParameters v4dhcpParms;
1840 DHCPParameters v6dhcpParms;
Ed Tanous0627a2c2018-11-29 17:09:23 -08001841
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001842 if (!json_util::readJson(
1843 req, res, "HostName", hostname, "IPv4StaticAddresses",
1844 ipv4StaticAddresses, "MACAddress", macAddress,
1845 "StaticNameServers", staticNameServers, "IPv6DefaultGateway",
1846 ipv6DefaultGateway, "IPv6StaticAddresses", ipv6StaticAddresses,
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001847 "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, "InterfaceEnabled",
1848 interfaceEnabled))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849 {
1850 return;
1851 }
Jennifer Leeda131a92019-04-24 15:13:55 -07001852 if (dhcpv4)
1853 {
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001854 if (!json_util::readJson(*dhcpv4, res, "DHCPEnabled",
1855 v4dhcpParms.dhcpv4Enabled, "UseDNSServers",
1856 v4dhcpParms.useDNSServers, "UseNTPServers",
1857 v4dhcpParms.useNTPServers, "UseDomainName",
1858 v4dhcpParms.useUseDomainName))
1859 {
1860 return;
1861 }
1862 }
1863
1864 if (dhcpv6)
1865 {
1866 if (!json_util::readJson(*dhcpv6, res, "OperatingMode",
1867 v6dhcpParms.dhcpv6OperatingMode,
1868 "UseDNSServers", v6dhcpParms.useDNSServers,
1869 "UseNTPServers", v6dhcpParms.useNTPServers,
1870 "UseDomainName",
1871 v6dhcpParms.useUseDomainName))
1872 {
1873 return;
1874 }
Jennifer Leeda131a92019-04-24 15:13:55 -07001875 }
1876
Johnathan Mantey01784822019-06-18 12:44:21 -07001877 // Get single eth interface data, and call the below callback for
1878 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07001879 getEthernetIfaceData(
1880 iface_id,
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001881 [this, asyncResp, iface_id, hostname = std::move(hostname),
1882 macAddress = std::move(macAddress),
Ravi Tejad1d50812019-06-23 16:20:27 -05001883 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001884 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001885 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001886 staticNameServers = std::move(staticNameServers),
1887 dhcpv4 = std::move(dhcpv4), dhcpv6 = std::move(dhcpv6),
1888 v4dhcpParms = std::move(v4dhcpParms),
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001889 v6dhcpParms = std::move(v6dhcpParms),
1890 interfaceEnabled = std::move(interfaceEnabled)](
Ed Tanous4a0cb852018-10-15 07:55:04 -07001891 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001892 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001893 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001894 if (!success)
1895 {
1896 // ... otherwise return error
1897 // TODO(Pawel)consider distinguish between non existing
1898 // object, and other errors
Sunitha Harishfda13ad2019-03-21 11:01:24 -05001899 messages::resourceNotFound(asyncResp->res,
1900 "Ethernet Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001901 return;
1902 }
1903
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -07001904 if (dhcpv4 || dhcpv6)
1905 {
1906 handleDHCPPatch(iface_id, ethData, std::move(v4dhcpParms),
1907 std::move(v6dhcpParms), asyncResp);
1908 }
1909
Ed Tanous0627a2c2018-11-29 17:09:23 -08001910 if (hostname)
1911 {
1912 handleHostnamePatch(*hostname, asyncResp);
1913 }
1914
Ratan Guptad5776652019-03-03 08:47:22 +05301915 if (macAddress)
1916 {
1917 handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1918 }
1919
Ravi Tejad1d50812019-06-23 16:20:27 -05001920 if (ipv4StaticAddresses)
1921 {
Ed Tanous537174c2018-12-10 15:09:31 -08001922 // TODO(ed) for some reason the capture of ipv4Addresses
Johnathan Mantey01784822019-06-18 12:44:21 -07001923 // above is returning a const value, not a non-const
1924 // value. This doesn't really work for us, as we need to
1925 // be able to efficiently move out the intermedia
1926 // nlohmann::json objects. This makes a copy of the
1927 // structure, and operates on that, but could be done
1928 // more efficiently
Ravi Tejad1d50812019-06-23 16:20:27 -05001929 nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
Johnathan Mantey01784822019-06-18 12:44:21 -07001930 handleIPv4StaticPatch(iface_id, ipv4Static, ipv4Data,
Ravi Tejad1d50812019-06-23 16:20:27 -05001931 asyncResp);
Ed Tanous0627a2c2018-11-29 17:09:23 -08001932 }
1933
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -05001934 if (staticNameServers)
1935 {
1936 handleStaticNameServersPatch(iface_id, *staticNameServers,
1937 asyncResp);
1938 }
Ravi Teja9a6fc6f2019-04-16 02:43:13 -05001939
1940 if (ipv6DefaultGateway)
1941 {
1942 messages::propertyNotWritable(asyncResp->res,
1943 "IPv6DefaultGateway");
1944 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001945
1946 if (ipv6StaticAddresses)
1947 {
1948 nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1949 handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
Johnathan Mantey01784822019-06-18 12:44:21 -07001950 ipv6Data, asyncResp);
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001951 }
Johnathan Manteyeeedda22019-10-29 16:09:52 -07001952
1953 if (interfaceEnabled)
1954 {
1955 setEthernetInterfaceBoolProperty(
1956 iface_id, "NICEnabled", *interfaceEnabled, asyncResp);
1957 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001958 });
1959 }
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001960};
1961
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001962/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001963 * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1964 * Schema
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001965 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07001966class VlanNetworkInterface : public Node
1967{
1968 public:
1969 /*
1970 * Default Constructor
1971 */
1972 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001973 VlanNetworkInterface(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07001974 Node(app,
Ed Tanous0f74e642018-11-12 15:17:05 -08001975 "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
Ed Tanous4a0cb852018-10-15 07:55:04 -07001976 std::string(), std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001977 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001978 entityPrivileges = {
1979 {boost::beast::http::verb::get, {{"Login"}}},
1980 {boost::beast::http::verb::head, {{"Login"}}},
1981 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1982 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1983 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1984 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02001985 }
1986
Ed Tanous1abe55e2018-09-05 08:30:59 -07001987 private:
Ed Tanous0f74e642018-11-12 15:17:05 -08001988 void parseInterfaceData(
1989 nlohmann::json &json_response, const std::string &parent_iface_id,
1990 const std::string &iface_id, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05001991 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07001992 const boost::container::flat_set<IPv6AddressData> &ipv6Data)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001993 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001994 // Fill out obvious data...
Ed Tanous4a0cb852018-10-15 07:55:04 -07001995 json_response["Id"] = iface_id;
1996 json_response["@odata.id"] =
1997 "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1998 "/VLANs/" + iface_id;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001999
Ed Tanous4a0cb852018-10-15 07:55:04 -07002000 json_response["VLANEnable"] = true;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002001 if (!ethData.vlan_id.empty())
Ed Tanous4a0cb852018-10-15 07:55:04 -07002002 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002003 json_response["VLANId"] = ethData.vlan_id.back();
Ed Tanous4a0cb852018-10-15 07:55:04 -07002004 }
Ed Tanousa434f2b2018-07-27 13:04:22 -07002005 }
2006
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002007 bool verifyNames(const std::string &parent, const std::string &iface)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002008 {
2009 if (!boost::starts_with(iface, parent + "_"))
2010 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002011 return false;
2012 }
2013 else
2014 {
2015 return true;
2016 }
2017 }
2018
2019 /**
2020 * Functions triggers appropriate requests on DBus
2021 */
2022 void doGet(crow::Response &res, const crow::Request &req,
2023 const std::vector<std::string> &params) override
2024 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002025 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2026 // TODO(Pawel) this shall be parameterized call (two params) to get
Ed Tanous1abe55e2018-09-05 08:30:59 -07002027 // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
2028 // Check if there is required param, truly entering this shall be
2029 // impossible.
2030 if (params.size() != 2)
2031 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002032 messages::internalError(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002033 res.end();
Kowalski, Kamil927a5052018-07-03 14:16:46 +02002034 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002035 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02002036
Ed Tanous4a0cb852018-10-15 07:55:04 -07002037 const std::string &parent_iface_id = params[0];
2038 const std::string &iface_id = params[1];
Ed Tanous0f74e642018-11-12 15:17:05 -08002039 res.jsonValue["@odata.type"] =
2040 "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
Ed Tanous0f74e642018-11-12 15:17:05 -08002041 res.jsonValue["Name"] = "VLAN Network Interface";
Kowalski, Kamil927a5052018-07-03 14:16:46 +02002042
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002043 if (!verifyNames(parent_iface_id, iface_id))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002044 {
2045 return;
2046 }
Kowalski, Kamil927a5052018-07-03 14:16:46 +02002047
Johnathan Mantey01784822019-06-18 12:44:21 -07002048 // Get single eth interface data, and call the below callback for
2049 // JSON preparation
Ed Tanous4a0cb852018-10-15 07:55:04 -07002050 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002051 params[1],
2052 [this, asyncResp, parent_iface_id{std::string(params[0])},
2053 iface_id{std::string(params[1])}](
Ed Tanous4a0cb852018-10-15 07:55:04 -07002054 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002055 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07002056 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002057 if (success && ethData.vlan_id.size() != 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002058 {
Ed Tanous0f74e642018-11-12 15:17:05 -08002059 parseInterfaceData(asyncResp->res.jsonValue,
2060 parent_iface_id, iface_id, ethData,
Johnathan Mantey01784822019-06-18 12:44:21 -07002061 ipv4Data, ipv6Data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002062 }
2063 else
2064 {
2065 // ... otherwise return error
2066 // TODO(Pawel)consider distinguish between non existing
2067 // object, and other errors
Jason M. Billsf12894f2018-10-09 12:45:45 -07002068 messages::resourceNotFound(
2069 asyncResp->res, "VLAN Network Interface", iface_id);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002070 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002071 });
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002072 }
2073
Ed Tanous1abe55e2018-09-05 08:30:59 -07002074 void doPatch(crow::Response &res, const crow::Request &req,
2075 const std::vector<std::string> &params) override
2076 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002077 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002078 if (params.size() != 2)
2079 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002080 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002081 return;
2082 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002083
Ed Tanous1abe55e2018-09-05 08:30:59 -07002084 const std::string &parentIfaceId = params[0];
2085 const std::string &ifaceId = params[1];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002086
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002087 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002089 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2090 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002091 return;
2092 }
2093
Ed Tanous0627a2c2018-11-29 17:09:23 -08002094 bool vlanEnable = false;
2095 uint64_t vlanId = 0;
2096
2097 if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
2098 vlanId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002099 {
2100 return;
2101 }
2102
Johnathan Mantey01784822019-06-18 12:44:21 -07002103 // Get single eth interface data, and call the below callback for
2104 // JSON preparation
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002105 getEthernetIfaceData(
2106 params[1],
Ed Tanous271584a2019-07-09 16:24:22 -07002107 [asyncResp, parentIfaceId{std::string(params[0])},
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002108 ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
2109 const bool &success, const EthernetInterfaceData &ethData,
2110 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07002111 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002112 if (success && !ethData.vlan_id.empty())
Sunitha Harish08244d02019-04-01 03:57:25 -05002113 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002114 auto callback =
2115 [asyncResp](const boost::system::error_code ec) {
2116 if (ec)
2117 {
2118 messages::internalError(asyncResp->res);
2119 }
2120 };
2121
2122 if (vlanEnable == true)
2123 {
2124 crow::connections::systemBus->async_method_call(
2125 std::move(callback), "xyz.openbmc_project.Network",
2126 "/xyz/openbmc_project/network/" + ifaceId,
2127 "org.freedesktop.DBus.Properties", "Set",
2128 "xyz.openbmc_project.Network.VLAN", "Id",
2129 std::variant<uint32_t>(vlanId));
2130 }
2131 else
2132 {
2133 BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
2134 "vlan interface";
2135 crow::connections::systemBus->async_method_call(
2136 std::move(callback), "xyz.openbmc_project.Network",
2137 std::string("/xyz/openbmc_project/network/") +
2138 ifaceId,
2139 "xyz.openbmc_project.Object.Delete", "Delete");
2140 }
Sunitha Harish08244d02019-04-01 03:57:25 -05002141 }
2142 else
2143 {
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002144 // TODO(Pawel)consider distinguish between non existing
2145 // object, and other errors
2146 messages::resourceNotFound(
2147 asyncResp->res, "VLAN Network Interface", ifaceId);
2148 return;
Sunitha Harish08244d02019-04-01 03:57:25 -05002149 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002150 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002151 }
2152
2153 void doDelete(crow::Response &res, const crow::Request &req,
2154 const std::vector<std::string> &params) override
2155 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002156 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002157 if (params.size() != 2)
2158 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002159 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002160 return;
2161 }
2162
2163 const std::string &parentIfaceId = params[0];
2164 const std::string &ifaceId = params[1];
2165
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002166 if (!verifyNames(parentIfaceId, ifaceId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002167 {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002168 messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2169 ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002170 return;
2171 }
2172
Johnathan Mantey01784822019-06-18 12:44:21 -07002173 // Get single eth interface data, and call the below callback for
2174 // JSON preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002175 getEthernetIfaceData(
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002176 params[1],
Ed Tanous271584a2019-07-09 16:24:22 -07002177 [asyncResp, parentIfaceId{std::string(params[0])},
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002178 ifaceId{std::string(params[1])}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002179 const bool &success, const EthernetInterfaceData &ethData,
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002180 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
Johnathan Mantey01784822019-06-18 12:44:21 -07002181 const boost::container::flat_set<IPv6AddressData> &ipv6Data) {
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002182 if (success && !ethData.vlan_id.empty())
Jason M. Billsf12894f2018-10-09 12:45:45 -07002183 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002184 auto callback =
2185 [asyncResp](const boost::system::error_code ec) {
2186 if (ec)
2187 {
2188 messages::internalError(asyncResp->res);
2189 }
2190 };
2191 crow::connections::systemBus->async_method_call(
2192 std::move(callback), "xyz.openbmc_project.Network",
2193 std::string("/xyz/openbmc_project/network/") + ifaceId,
2194 "xyz.openbmc_project.Object.Delete", "Delete");
2195 }
2196 else
2197 {
2198 // ... otherwise return error
2199 // TODO(Pawel)consider distinguish between non existing
2200 // object, and other errors
2201 messages::resourceNotFound(
2202 asyncResp->res, "VLAN Network Interface", ifaceId);
2203 }
2204 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002205 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002206};
2207
2208/**
2209 * VlanNetworkInterfaceCollection derived class for delivering
2210 * VLANNetworkInterface Collection Schema
2211 */
Ed Tanous1abe55e2018-09-05 08:30:59 -07002212class VlanNetworkInterfaceCollection : public Node
2213{
2214 public:
2215 template <typename CrowApp>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002216 VlanNetworkInterfaceCollection(CrowApp &app) :
Ed Tanous4a0cb852018-10-15 07:55:04 -07002217 Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
2218 std::string())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002219 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002220 entityPrivileges = {
2221 {boost::beast::http::verb::get, {{"Login"}}},
2222 {boost::beast::http::verb::head, {{"Login"}}},
2223 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2224 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2225 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2226 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002227 }
2228
Ed Tanous1abe55e2018-09-05 08:30:59 -07002229 private:
2230 /**
2231 * Functions triggers appropriate requests on DBus
2232 */
2233 void doGet(crow::Response &res, const crow::Request &req,
2234 const std::vector<std::string> &params) override
2235 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002236 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002237 if (params.size() != 1)
2238 {
2239 // This means there is a problem with the router
Jason M. Billsf12894f2018-10-09 12:45:45 -07002240 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002241 return;
Ed Tanous8ceb2ec2018-08-13 11:11:56 -07002242 }
2243
Ed Tanous4a0cb852018-10-15 07:55:04 -07002244 const std::string &rootInterfaceName = params[0];
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002245
Ed Tanous4a0cb852018-10-15 07:55:04 -07002246 // Get eth interface list, and call the below callback for JSON
Ed Tanous1abe55e2018-09-05 08:30:59 -07002247 // preparation
Jason M. Billsf12894f2018-10-09 12:45:45 -07002248 getEthernetIfaceList(
Ed Tanous43b761d2019-02-13 20:10:56 -08002249 [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
Jason M. Billsf12894f2018-10-09 12:45:45 -07002250 const bool &success,
Ed Tanous4c9afe42019-05-03 16:59:57 -07002251 const boost::container::flat_set<std::string> &iface_list) {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002252 if (!success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002253 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002254 messages::internalError(asyncResp->res);
2255 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002256 }
Ed Tanous4c9afe42019-05-03 16:59:57 -07002257
2258 if (iface_list.find(rootInterfaceName) == iface_list.end())
2259 {
2260 messages::resourceNotFound(asyncResp->res,
2261 "VLanNetworkInterfaceCollection",
2262 rootInterfaceName);
2263 return;
2264 }
2265
Ed Tanous0f74e642018-11-12 15:17:05 -08002266 asyncResp->res.jsonValue["@odata.type"] =
2267 "#VLanNetworkInterfaceCollection."
2268 "VLanNetworkInterfaceCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002269 asyncResp->res.jsonValue["Name"] =
2270 "VLAN Network Interface Collection";
Ed Tanous4a0cb852018-10-15 07:55:04 -07002271
Jason M. Billsf12894f2018-10-09 12:45:45 -07002272 nlohmann::json iface_array = nlohmann::json::array();
2273
2274 for (const std::string &iface_item : iface_list)
2275 {
2276 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
2277 {
2278 iface_array.push_back(
2279 {{"@odata.id",
2280 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2281 rootInterfaceName + "/VLANs/" + iface_item}});
2282 }
2283 }
2284
Jason M. Billsf12894f2018-10-09 12:45:45 -07002285 asyncResp->res.jsonValue["Members@odata.count"] =
2286 iface_array.size();
2287 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
2288 asyncResp->res.jsonValue["@odata.id"] =
2289 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
2290 rootInterfaceName + "/VLANs";
2291 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002292 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002293
Ed Tanous1abe55e2018-09-05 08:30:59 -07002294 void doPost(crow::Response &res, const crow::Request &req,
2295 const std::vector<std::string> &params) override
2296 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002297 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002298 if (params.size() != 1)
2299 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002300 messages::internalError(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002301 return;
2302 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002303 bool vlanEnable = false;
Ed Tanous0627a2c2018-11-29 17:09:23 -08002304 uint32_t vlanId = 0;
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002305 if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2306 vlanEnable))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002307 {
Ed Tanous4a0cb852018-10-15 07:55:04 -07002308 return;
2309 }
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002310 // Need both vlanId and vlanEnable to service this request
2311 if (!vlanId)
2312 {
2313 messages::propertyMissing(asyncResp->res, "VLANId");
2314 }
2315 if (!vlanEnable)
2316 {
2317 messages::propertyMissing(asyncResp->res, "VLANEnable");
2318 }
Ed Tanous271584a2019-07-09 16:24:22 -07002319 if (static_cast<bool>(vlanId) ^ vlanEnable)
Sunitha Harishfda13ad2019-03-21 11:01:24 -05002320 {
2321 return;
2322 }
2323
Ed Tanous4a0cb852018-10-15 07:55:04 -07002324 const std::string &rootInterfaceName = params[0];
Ed Tanous4a0cb852018-10-15 07:55:04 -07002325 auto callback = [asyncResp](const boost::system::error_code ec) {
2326 if (ec)
2327 {
2328 // TODO(ed) make more consistent error messages based on
2329 // phosphor-network responses
Jason M. Billsf12894f2018-10-09 12:45:45 -07002330 messages::internalError(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002331 return;
2332 }
Jason M. Billsf12894f2018-10-09 12:45:45 -07002333 messages::created(asyncResp->res);
Ed Tanous4a0cb852018-10-15 07:55:04 -07002334 };
2335 crow::connections::systemBus->async_method_call(
2336 std::move(callback), "xyz.openbmc_project.Network",
2337 "/xyz/openbmc_project/network",
2338 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
Ed Tanous0627a2c2018-11-29 17:09:23 -08002339 rootInterfaceName, vlanId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002340 }
Kowalski, Kamile439f0f2018-05-21 08:13:57 +02002341};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002342} // namespace redfish