blob: bfe924c7fb3a668fd4a5bee37bb8371682a1ce1f [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
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700253ServiceCache::ServiceCache(const std::string& intf, const std::string& path)
254 : intf(intf), path(path), cachedService(std::experimental::nullopt),
255 cachedBusName(std::experimental::nullopt)
256{
257}
258
259ServiceCache::ServiceCache(std::string&& intf, std::string&& path)
260 : intf(std::move(intf)), path(std::move(path)),
261 cachedService(std::experimental::nullopt),
262 cachedBusName(std::experimental::nullopt)
263{
264}
265
266const std::string& ServiceCache::getService(sdbusplus::bus::bus& bus)
267{
268 if (!isValid(bus))
269 {
270 cachedBusName = bus.get_unique_name();
271 cachedService = ::ipmi::getService(bus, intf, path);
272 }
273 return cachedService.value();
274}
275
276void ServiceCache::invalidate()
277{
278 cachedBusName = std::experimental::nullopt;
279 cachedService = std::experimental::nullopt;
280}
281
282sdbusplus::message::message ServiceCache::newMethodCall(
283 sdbusplus::bus::bus& bus, const char *intf, const char *method)
284{
285 return bus.new_method_call(getService(bus).c_str(), path.c_str(),
286 intf, method);
287}
288
289bool ServiceCache::isValid(sdbusplus::bus::bus& bus) const
290{
291 return cachedService && cachedBusName == bus.get_unique_name();
292}
293
Tom Josephbe703f72017-03-09 12:34:35 +0530294std::string getService(sdbusplus::bus::bus& bus,
295 const std::string& intf,
296 const std::string& path)
297{
298 auto mapperCall = bus.new_method_call("xyz.openbmc_project.ObjectMapper",
Leonel Gonzalezd15e6c92017-03-16 13:47:58 -0500299 "/xyz/openbmc_project/object_mapper",
Tom Josephbe703f72017-03-09 12:34:35 +0530300 "xyz.openbmc_project.ObjectMapper",
301 "GetObject");
302
303 mapperCall.append(path);
304 mapperCall.append(std::vector<std::string>({intf}));
305
306 auto mapperResponseMsg = bus.call(mapperCall);
307
308 if (mapperResponseMsg.is_method_error())
309 {
310 throw std::runtime_error("ERROR in mapper call");
311 }
312
313 std::map<std::string, std::vector<std::string>> mapperResponse;
314 mapperResponseMsg.read(mapperResponse);
315
316 if (mapperResponse.begin() == mapperResponse.end())
317 {
318 throw std::runtime_error("ERROR in reading the mapper response");
319 }
320
321 return mapperResponse.begin()->first;
322}
323
Ratan Guptab8e99552017-07-27 07:07:48 +0530324ipmi::ObjectTree getAllDbusObjects(sdbusplus::bus::bus& bus,
325 const std::string& serviceRoot,
326 const std::string& interface,
327 const std::string& match)
328{
329 std::vector<std::string> interfaces;
330 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530331
Ratan Guptab8e99552017-07-27 07:07:48 +0530332 auto depth = 0;
333
334 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
335 MAPPER_OBJ,
336 MAPPER_INTF,
337 "GetSubTree");
338
339 mapperCall.append(serviceRoot, depth, interfaces);
340
341 auto mapperReply = bus.call(mapperCall);
342 if (mapperReply.is_method_error())
343 {
344 log<level::ERR>("Error in mapper call",
345 entry("SERVICEROOT=%s",serviceRoot.c_str()),
346 entry("INTERFACE=%s", interface.c_str()));
347
348 elog<InternalFailure>();
349 }
350
351 ObjectTree objectTree;
352 mapperReply.read(objectTree);
353
354 for (auto it = objectTree.begin(); it != objectTree.end();)
355 {
356 if (it->first.find(match) == std::string::npos)
357 {
358 it = objectTree.erase(it);
359 }
360 else
361 {
362 ++it;
363 }
364 }
365
366 return objectTree;
367}
368
369void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
370 const std::string& serviceRoot,
371 const std::string& interface,
372 const std::string& match)
373{
374 try
375 {
376 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
377
378 for (auto& object : objectTree)
379 {
380 method_no_args::callDbusMethod(bus,
381 object.second.begin()->first,
382 object.first,
383 DELETE_INTERFACE, "Delete");
384 }
385 }
386 catch (InternalFailure& e)
387 {
388 log<level::INFO>("Unable to delete the objects having",
389 entry("INTERFACE=%s", interface.c_str()),
390 entry("SERVICE=%s", serviceRoot.c_str()));
391 }
392}
393
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530394ObjectTree getAllAncestors(sdbusplus::bus::bus& bus,
395 const std::string& path,
396 InterfaceList&& interfaces)
397{
398 auto convertToString = [](InterfaceList& interfaces) -> std::string
399 {
400 std::string intfStr;
401 for (const auto& intf : interfaces)
402 {
403 intfStr += "," + intf;
404 }
405 return intfStr;
406 };
407
408 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
409 MAPPER_OBJ,
410 MAPPER_INTF,
411 "GetAncestors");
412 mapperCall.append(path, interfaces);
413
414 auto mapperReply = bus.call(mapperCall);
415 if (mapperReply.is_method_error())
416 {
417 log<level::ERR>("Error in mapper call",
418 entry("PATH=%s", path.c_str()),
419 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500420 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530421
422 elog<InternalFailure>();
423 }
424
425 ObjectTree objectTree;
426 mapperReply.read(objectTree);
427
428 if (objectTree.empty())
429 {
Patrick Venturef0c48782017-09-21 18:48:51 -0700430 log<level::ERR>("No Object has implemented the interface",
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530431 entry("PATH=%s", path.c_str()),
432 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500433 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530434 elog<InternalFailure>();
435 }
436
437 return objectTree;
438}
Ratan Guptab8e99552017-07-27 07:07:48 +0530439
440namespace method_no_args
441{
442
443void callDbusMethod(sdbusplus::bus::bus& bus,
444 const std::string& service,
445 const std::string& objPath,
446 const std::string& interface,
447 const std::string& method)
448
449{
450 auto busMethod = bus.new_method_call(
451 service.c_str(),
452 objPath.c_str(),
453 interface.c_str(),
454 method.c_str());
455
456 auto reply = bus.call(busMethod);
457
458 if (reply.is_method_error())
459 {
460 log<level::ERR>("Failed to execute method",
461 entry("METHOD=%s", method.c_str()),
462 entry("PATH=%s", objPath.c_str()),
463 entry("INTERFACE=%s", interface.c_str()));
464 elog<InternalFailure>();
465 }
466}
467
468}// namespace method_no_args
469
470namespace network
471{
472
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500473bool isLinkLocalIP(const std::string& address)
474{
475 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
476}
477
Ratan Guptab8e99552017-07-27 07:07:48 +0530478void createIP(sdbusplus::bus::bus& bus,
479 const std::string& service,
480 const std::string& objPath,
481 const std::string& protocolType,
482 const std::string& ipaddress,
483 uint8_t prefix)
484{
485 std::string gateway = "";
486
487 auto busMethod = bus.new_method_call(
488 service.c_str(),
489 objPath.c_str(),
490 IP_CREATE_INTERFACE,
491 "IP");
492
493 busMethod.append(protocolType, ipaddress, prefix, gateway);
494
495 auto reply = bus.call(busMethod);
496
497 if (reply.is_method_error())
498 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500499 log<level::ERR>("Failed to execute method",
Ratan Guptab8e99552017-07-27 07:07:48 +0530500 entry("METHOD=%s", "IP"),
501 entry("PATH=%s", objPath.c_str()));
502 elog<InternalFailure>();
503 }
504
505}
506
Ratan Gupta533d03b2017-07-30 10:39:22 +0530507void createVLAN(sdbusplus::bus::bus& bus,
508 const std::string& service,
509 const std::string& objPath,
510 const std::string& interfaceName,
511 uint32_t vlanID)
512{
513 auto busMethod = bus.new_method_call(
514 service.c_str(),
515 objPath.c_str(),
516 VLAN_CREATE_INTERFACE,
517 "VLAN");
518
519 busMethod.append(interfaceName, vlanID);
520
521 auto reply = bus.call(busMethod);
522
523 if (reply.is_method_error())
524 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -0500525 log<level::ERR>("Failed to execute method",
Ratan Gupta533d03b2017-07-30 10:39:22 +0530526 entry("METHOD=%s", "VLAN"),
527 entry("PATH=%s", objPath.c_str()));
528 elog<InternalFailure>();
529 }
530
531}
532
Ratan Guptab8e99552017-07-27 07:07:48 +0530533uint8_t toPrefix(int addressFamily, const std::string& subnetMask)
534{
535 if (addressFamily == AF_INET6)
536 {
537 return 0;
538 }
539
540 uint32_t buff {};
541
542 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
543 if (rc <= 0)
544 {
545 log<level::ERR>("inet_pton failed:",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -0500546 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Guptab8e99552017-07-27 07:07:48 +0530547 return 0;
548 }
549
550 buff = be32toh(buff);
551 // total no of bits - total no of leading zero == total no of ones
552 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
553 {
554 return __builtin_popcount(buff);
555 }
556 else
557 {
558 log<level::ERR>("Invalid Mask",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -0500559 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Guptab8e99552017-07-27 07:07:48 +0530560 return 0;
561 }
562}
563
Ratan Gupta533d03b2017-07-30 10:39:22 +0530564uint32_t getVLAN(const std::string& path)
565{
566 // Path would be look like
567 // /xyz/openbmc_project/network/eth0_443/ipv4
568
569 uint32_t vlanID = 0;
570 try
571 {
572 auto intfObjectPath = path.substr(0,
573 path.find(IP_TYPE) - 1);
574
575 auto intfName = intfObjectPath.substr(intfObjectPath.rfind("/") + 1);
576
577 auto index = intfName.find("_");
578 if (index != std::string::npos)
579 {
580 auto str = intfName.substr(index + 1);
581 vlanID = std::stoul(str);
582 }
583 }
584 catch (std::exception & e)
585 {
Gunnar Mills8991dd62017-10-25 17:11:29 -0500586 log<level::ERR>("Exception occurred during getVLAN",
Ratan Gupta533d03b2017-07-30 10:39:22 +0530587 entry("PATH=%s",path.c_str()),
Gunnar Mills5b801e42017-10-19 17:11:42 -0500588 entry("EXCEPTION=%s", e.what()));
Ratan Gupta533d03b2017-07-30 10:39:22 +0530589 }
590 return vlanID;
591}
592
Ratan Guptab8e99552017-07-27 07:07:48 +0530593} // namespace network
Tom Josephbe703f72017-03-09 12:34:35 +0530594} // namespace ipmi