blob: bd8fadea8c8e90b6ed3f564153b8a2a1b48625bb [file] [log] [blame]
Tom Josephbe703f72017-03-09 12:34:35 +05301#include "utils.hpp"
Ratan Guptacc8feb42017-07-25 21:52:10 +05302#include <phosphor-logging/log.hpp>
3#include <phosphor-logging/elog-errors.hpp>
4#include "xyz/openbmc_project/Common/error.hpp"
Tom Josephbe703f72017-03-09 12:34:35 +05305
Ratan Guptab8e99552017-07-27 07:07:48 +05306#include <arpa/inet.h>
7#include <dirent.h>
8#include <net/if.h>
9
Tom Josephbe703f72017-03-09 12:34:35 +053010namespace ipmi
11{
12
Ratan Guptacc8feb42017-07-25 21:52:10 +053013using namespace phosphor::logging;
14using namespace sdbusplus::xyz::openbmc_project::Common::Error;
15
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050016namespace network
17{
18
19/** @brief checks if the given ip is Link Local Ip or not.
20 * @param[in] ipaddress - IPAddress.
21 */
22bool isLinkLocalIP(const std::string& ipaddress);
23
24}
Ratan Guptacc8feb42017-07-25 21:52:10 +053025
26//TODO There may be cases where an interface is implemented by multiple
27// objects,to handle such cases we are interested on that object
28// which are on interested busname.
29// Currently mapper doesn't give the readable busname(gives busid) so we can't
30// use busname to find the object,will do later once the support is there.
31
Ratan Gupta01d4bd12017-08-07 15:53:25 +053032DbusObjectInfo getDbusObject(sdbusplus::bus::bus& bus,
33 const std::string& interface,
Ratan Guptacc8feb42017-07-25 21:52:10 +053034 const std::string& serviceRoot,
35 const std::string& match)
36{
37 std::vector<DbusInterface> interfaces;
38 interfaces.emplace_back(interface);
39
Ratan Guptacc8feb42017-07-25 21:52:10 +053040 auto depth = 0;
41
42 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
43 MAPPER_OBJ,
44 MAPPER_INTF,
45 "GetSubTree");
46
47 mapperCall.append(serviceRoot, depth, interfaces);
48
49 auto mapperReply = bus.call(mapperCall);
50 if (mapperReply.is_method_error())
51 {
52 log<level::ERR>("Error in mapper call");
53 elog<InternalFailure>();
54 }
55
56 ObjectTree objectTree;
57 mapperReply.read(objectTree);
58
59 if (objectTree.empty())
60 {
Patrick Venturef0c48782017-09-21 18:48:51 -070061 log<level::ERR>("No Object has implemented the interface",
Ratan Guptacc8feb42017-07-25 21:52:10 +053062 entry("INTERFACE=%s", interface.c_str()));
63 elog<InternalFailure>();
64 }
65
66 DbusObjectInfo objectInfo;
67
68 // if match is empty then return the first object
69 if(match == "")
70 {
71 objectInfo = std::make_pair(objectTree.begin()->first,
72 std::move(objectTree.begin()->second.begin()->first));
73 return objectInfo;
74 }
75
76 // else search the match string in the object path
77 auto objectFound = false;
78 for (auto& object : objectTree)
79 {
80 if(object.first.find(match) != std::string::npos)
81 {
82 objectFound = true;
83 objectInfo = make_pair(object.first,
84 std::move(object.second.begin()->first));
85 break;
86 }
87 }
88
89 if(!objectFound)
90 {
91 log<level::ERR>("Failed to find object which matches",
92 entry("MATCH=%s", match.c_str()));
93 elog<InternalFailure>();
94 }
95 return objectInfo;
96
97}
98
Ratan Guptadd646202017-11-21 17:46:59 +053099DbusObjectInfo getIPObject(sdbusplus::bus::bus& bus,
100 const std::string& interface,
101 const std::string& serviceRoot,
102 const std::string& match)
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500103{
104 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
105
106 if (objectTree.empty())
107 {
108 log<level::ERR>("No Object has implemented the IP interface",
109 entry("INTERFACE=%s", interface.c_str()));
110 elog<InternalFailure>();
111 }
112
Ratan Guptadd646202017-11-21 17:46:59 +0530113 DbusObjectInfo objectInfo;
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500114
115 for (auto& object : objectTree)
116 {
117 auto variant = ipmi::getDbusProperty(
118 bus,
119 object.second.begin()->first,
120 object.first,
121 ipmi::network::IP_INTERFACE,
122 "Address");
123
Ratan Guptadd646202017-11-21 17:46:59 +0530124 objectInfo = std::make_pair(object.first, object.second.begin()->first);
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500125
126 // if LinkLocalIP found look for Non-LinkLocalIP
Ratan Guptadd646202017-11-21 17:46:59 +0530127 if (ipmi::network::isLinkLocalIP(variant.get<std::string>()))
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500128 {
129 continue;
130 }
131 else
132 {
133 break;
134 }
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500135 }
Ratan Guptadd646202017-11-21 17:46:59 +0530136 return objectInfo;
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500137}
138
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530139Value getDbusProperty(sdbusplus::bus::bus& bus,
140 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530141 const std::string& objPath,
142 const std::string& interface,
143 const std::string& property)
144{
145
146 Value value;
147
Ratan Guptacc8feb42017-07-25 21:52:10 +0530148 auto method = bus.new_method_call(
149 service.c_str(),
150 objPath.c_str(),
151 PROP_INTF,
152 METHOD_GET);
153
154 method.append(interface, property);
155
156 auto reply = bus.call(method);
157
158 if (reply.is_method_error())
159 {
160 log<level::ERR>("Failed to get property",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500161 entry("PROPERTY=%s", property.c_str()),
162 entry("PATH=%s", objPath.c_str()),
163 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptacc8feb42017-07-25 21:52:10 +0530164 elog<InternalFailure>();
165 }
166
167 reply.read(value);
168
169 return value;
170}
171
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530172PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus,
173 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530174 const std::string& objPath,
175 const std::string& interface)
176{
177 PropertyMap properties;
Ratan Guptacc8feb42017-07-25 21:52:10 +0530178
179 auto method = bus.new_method_call(
180 service.c_str(),
181 objPath.c_str(),
182 PROP_INTF,
183 METHOD_GET_ALL);
184
185 method.append(interface);
186
187 auto reply = bus.call(method);
188
189 if (reply.is_method_error())
190 {
191 log<level::ERR>("Failed to get all properties",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500192 entry("PATH=%s", objPath.c_str()),
193 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptacc8feb42017-07-25 21:52:10 +0530194 elog<InternalFailure>();
195 }
196
197 reply.read(properties);
198 return properties;
199}
200
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600201ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus,
202 const std::string& service,
203 const std::string& objPath)
204{
205 ipmi::ObjectValueTree interfaces;
206
207 auto method = bus.new_method_call(
208 service.c_str(),
209 objPath.c_str(),
210 "org.freedesktop.DBus.ObjectManager",
211 "GetManagedObjects");
212
213 auto reply = bus.call(method);
214
215 if (reply.is_method_error())
216 {
217 log<level::ERR>("Failed to get managed objects",
218 entry("PATH=%s", objPath.c_str()));
219 elog<InternalFailure>();
220 }
221
222 reply.read(interfaces);
223 return interfaces;
224}
225
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530226void setDbusProperty(sdbusplus::bus::bus& bus,
227 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530228 const std::string& objPath,
229 const std::string& interface,
230 const std::string& property,
231 const Value& value)
232{
Ratan Guptacc8feb42017-07-25 21:52:10 +0530233 auto method = bus.new_method_call(
234 service.c_str(),
235 objPath.c_str(),
236 PROP_INTF,
237 METHOD_SET);
238
239 method.append(interface, property, value);
240
241 if (!bus.call(method))
242 {
243 log<level::ERR>("Failed to set property",
244 entry("PROPERTY=%s", property.c_str()),
245 entry("PATH=%s",objPath.c_str()),
246 entry("INTERFACE=%s",interface.c_str()));
247 elog<InternalFailure>();
248 }
249
250}
251
252
Tom Josephbe703f72017-03-09 12:34:35 +0530253std::string getService(sdbusplus::bus::bus& bus,
254 const std::string& intf,
255 const std::string& path)
256{
257 auto mapperCall = bus.new_method_call("xyz.openbmc_project.ObjectMapper",
Leonel Gonzalezd15e6c92017-03-16 13:47:58 -0500258 "/xyz/openbmc_project/object_mapper",
Tom Josephbe703f72017-03-09 12:34:35 +0530259 "xyz.openbmc_project.ObjectMapper",
260 "GetObject");
261
262 mapperCall.append(path);
263 mapperCall.append(std::vector<std::string>({intf}));
264
265 auto mapperResponseMsg = bus.call(mapperCall);
266
267 if (mapperResponseMsg.is_method_error())
268 {
269 throw std::runtime_error("ERROR in mapper call");
270 }
271
272 std::map<std::string, std::vector<std::string>> mapperResponse;
273 mapperResponseMsg.read(mapperResponse);
274
275 if (mapperResponse.begin() == mapperResponse.end())
276 {
277 throw std::runtime_error("ERROR in reading the mapper response");
278 }
279
280 return mapperResponse.begin()->first;
281}
282
Ratan Guptab8e99552017-07-27 07:07:48 +0530283ipmi::ObjectTree getAllDbusObjects(sdbusplus::bus::bus& bus,
284 const std::string& serviceRoot,
285 const std::string& interface,
286 const std::string& match)
287{
288 std::vector<std::string> interfaces;
289 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530290
Ratan Guptab8e99552017-07-27 07:07:48 +0530291 auto depth = 0;
292
293 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
294 MAPPER_OBJ,
295 MAPPER_INTF,
296 "GetSubTree");
297
298 mapperCall.append(serviceRoot, depth, interfaces);
299
300 auto mapperReply = bus.call(mapperCall);
301 if (mapperReply.is_method_error())
302 {
303 log<level::ERR>("Error in mapper call",
304 entry("SERVICEROOT=%s",serviceRoot.c_str()),
305 entry("INTERFACE=%s", interface.c_str()));
306
307 elog<InternalFailure>();
308 }
309
310 ObjectTree objectTree;
311 mapperReply.read(objectTree);
312
313 for (auto it = objectTree.begin(); it != objectTree.end();)
314 {
315 if (it->first.find(match) == std::string::npos)
316 {
317 it = objectTree.erase(it);
318 }
319 else
320 {
321 ++it;
322 }
323 }
324
325 return objectTree;
326}
327
328void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
329 const std::string& serviceRoot,
330 const std::string& interface,
331 const std::string& match)
332{
333 try
334 {
335 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
336
337 for (auto& object : objectTree)
338 {
339 method_no_args::callDbusMethod(bus,
340 object.second.begin()->first,
341 object.first,
342 DELETE_INTERFACE, "Delete");
343 }
344 }
345 catch (InternalFailure& e)
346 {
347 log<level::INFO>("Unable to delete the objects having",
348 entry("INTERFACE=%s", interface.c_str()),
349 entry("SERVICE=%s", serviceRoot.c_str()));
350 }
351}
352
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530353ObjectTree getAllAncestors(sdbusplus::bus::bus& bus,
354 const std::string& path,
355 InterfaceList&& interfaces)
356{
357 auto convertToString = [](InterfaceList& interfaces) -> std::string
358 {
359 std::string intfStr;
360 for (const auto& intf : interfaces)
361 {
362 intfStr += "," + intf;
363 }
364 return intfStr;
365 };
366
367 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
368 MAPPER_OBJ,
369 MAPPER_INTF,
370 "GetAncestors");
371 mapperCall.append(path, interfaces);
372
373 auto mapperReply = bus.call(mapperCall);
374 if (mapperReply.is_method_error())
375 {
376 log<level::ERR>("Error in mapper call",
377 entry("PATH=%s", path.c_str()),
378 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500379 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530380
381 elog<InternalFailure>();
382 }
383
384 ObjectTree objectTree;
385 mapperReply.read(objectTree);
386
387 if (objectTree.empty())
388 {
Patrick Venturef0c48782017-09-21 18:48:51 -0700389 log<level::ERR>("No Object has implemented the interface",
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530390 entry("PATH=%s", path.c_str()),
391 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500392 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530393 elog<InternalFailure>();
394 }
395
396 return objectTree;
397}
Ratan Guptab8e99552017-07-27 07:07:48 +0530398
399namespace method_no_args
400{
401
402void callDbusMethod(sdbusplus::bus::bus& bus,
403 const std::string& service,
404 const std::string& objPath,
405 const std::string& interface,
406 const std::string& method)
407
408{
409 auto busMethod = bus.new_method_call(
410 service.c_str(),
411 objPath.c_str(),
412 interface.c_str(),
413 method.c_str());
414
415 auto reply = bus.call(busMethod);
416
417 if (reply.is_method_error())
418 {
419 log<level::ERR>("Failed to execute method",
420 entry("METHOD=%s", method.c_str()),
421 entry("PATH=%s", objPath.c_str()),
422 entry("INTERFACE=%s", interface.c_str()));
423 elog<InternalFailure>();
424 }
425}
426
427}// namespace method_no_args
428
429namespace network
430{
431
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500432bool isLinkLocalIP(const std::string& address)
433{
434 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
435}
436
Ratan Guptab8e99552017-07-27 07:07:48 +0530437void createIP(sdbusplus::bus::bus& bus,
438 const std::string& service,
439 const std::string& objPath,
440 const std::string& protocolType,
441 const std::string& ipaddress,
442 uint8_t prefix)
443{
444 std::string gateway = "";
445
446 auto busMethod = bus.new_method_call(
447 service.c_str(),
448 objPath.c_str(),
449 IP_CREATE_INTERFACE,
450 "IP");
451
452 busMethod.append(protocolType, ipaddress, prefix, gateway);
453
454 auto reply = bus.call(busMethod);
455
456 if (reply.is_method_error())
457 {
458 log<level::ERR>("Failed to excute method",
459 entry("METHOD=%s", "IP"),
460 entry("PATH=%s", objPath.c_str()));
461 elog<InternalFailure>();
462 }
463
464}
465
Ratan Gupta533d03b2017-07-30 10:39:22 +0530466void createVLAN(sdbusplus::bus::bus& bus,
467 const std::string& service,
468 const std::string& objPath,
469 const std::string& interfaceName,
470 uint32_t vlanID)
471{
472 auto busMethod = bus.new_method_call(
473 service.c_str(),
474 objPath.c_str(),
475 VLAN_CREATE_INTERFACE,
476 "VLAN");
477
478 busMethod.append(interfaceName, vlanID);
479
480 auto reply = bus.call(busMethod);
481
482 if (reply.is_method_error())
483 {
484 log<level::ERR>("Failed to excute method",
485 entry("METHOD=%s", "VLAN"),
486 entry("PATH=%s", objPath.c_str()));
487 elog<InternalFailure>();
488 }
489
490}
491
Ratan Guptab8e99552017-07-27 07:07:48 +0530492uint8_t toPrefix(int addressFamily, const std::string& subnetMask)
493{
494 if (addressFamily == AF_INET6)
495 {
496 return 0;
497 }
498
499 uint32_t buff {};
500
501 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
502 if (rc <= 0)
503 {
504 log<level::ERR>("inet_pton failed:",
505 entry("SUBNETMASK=%s", subnetMask));
506 return 0;
507 }
508
509 buff = be32toh(buff);
510 // total no of bits - total no of leading zero == total no of ones
511 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
512 {
513 return __builtin_popcount(buff);
514 }
515 else
516 {
517 log<level::ERR>("Invalid Mask",
518 entry("SUBNETMASK=%s", subnetMask));
519 return 0;
520 }
521}
522
Ratan Gupta533d03b2017-07-30 10:39:22 +0530523uint32_t getVLAN(const std::string& path)
524{
525 // Path would be look like
526 // /xyz/openbmc_project/network/eth0_443/ipv4
527
528 uint32_t vlanID = 0;
529 try
530 {
531 auto intfObjectPath = path.substr(0,
532 path.find(IP_TYPE) - 1);
533
534 auto intfName = intfObjectPath.substr(intfObjectPath.rfind("/") + 1);
535
536 auto index = intfName.find("_");
537 if (index != std::string::npos)
538 {
539 auto str = intfName.substr(index + 1);
540 vlanID = std::stoul(str);
541 }
542 }
543 catch (std::exception & e)
544 {
Gunnar Mills8991dd62017-10-25 17:11:29 -0500545 log<level::ERR>("Exception occurred during getVLAN",
Ratan Gupta533d03b2017-07-30 10:39:22 +0530546 entry("PATH=%s",path.c_str()),
Gunnar Mills5b801e42017-10-19 17:11:42 -0500547 entry("EXCEPTION=%s", e.what()));
Ratan Gupta533d03b2017-07-30 10:39:22 +0530548 }
549 return vlanID;
550}
551
Ratan Guptab8e99552017-07-27 07:07:48 +0530552} // namespace network
Tom Josephbe703f72017-03-09 12:34:35 +0530553} // namespace ipmi