blob: ea3a6aae8f666f68ee9e508178d17fbf60229345 [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
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050099std::string getIPAddress(sdbusplus::bus::bus& bus,
100 const std::string& interface,
101 const std::string& serviceRoot,
102 const std::string& match)
103{
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
113 std::string ipaddress;
114
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
124 ipaddress = std::move(variant.get<std::string>());
125
126 // if LinkLocalIP found look for Non-LinkLocalIP
127 if (ipmi::network::isLinkLocalIP(ipaddress))
128 {
129 continue;
130 }
131 else
132 {
133 break;
134 }
135
136 }
137
138 return ipaddress;
139
140}
141
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530142Value getDbusProperty(sdbusplus::bus::bus& bus,
143 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530144 const std::string& objPath,
145 const std::string& interface,
146 const std::string& property)
147{
148
149 Value value;
150
Ratan Guptacc8feb42017-07-25 21:52:10 +0530151 auto method = bus.new_method_call(
152 service.c_str(),
153 objPath.c_str(),
154 PROP_INTF,
155 METHOD_GET);
156
157 method.append(interface, property);
158
159 auto reply = bus.call(method);
160
161 if (reply.is_method_error())
162 {
163 log<level::ERR>("Failed to get property",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500164 entry("PROPERTY=%s", property.c_str()),
165 entry("PATH=%s", objPath.c_str()),
166 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptacc8feb42017-07-25 21:52:10 +0530167 elog<InternalFailure>();
168 }
169
170 reply.read(value);
171
172 return value;
173}
174
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530175PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus,
176 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530177 const std::string& objPath,
178 const std::string& interface)
179{
180 PropertyMap properties;
Ratan Guptacc8feb42017-07-25 21:52:10 +0530181
182 auto method = bus.new_method_call(
183 service.c_str(),
184 objPath.c_str(),
185 PROP_INTF,
186 METHOD_GET_ALL);
187
188 method.append(interface);
189
190 auto reply = bus.call(method);
191
192 if (reply.is_method_error())
193 {
194 log<level::ERR>("Failed to get all properties",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500195 entry("PATH=%s", objPath.c_str()),
196 entry("INTERFACE=%s", interface.c_str()));
Ratan Guptacc8feb42017-07-25 21:52:10 +0530197 elog<InternalFailure>();
198 }
199
200 reply.read(properties);
201 return properties;
202}
203
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530204void setDbusProperty(sdbusplus::bus::bus& bus,
205 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530206 const std::string& objPath,
207 const std::string& interface,
208 const std::string& property,
209 const Value& value)
210{
Ratan Guptacc8feb42017-07-25 21:52:10 +0530211 auto method = bus.new_method_call(
212 service.c_str(),
213 objPath.c_str(),
214 PROP_INTF,
215 METHOD_SET);
216
217 method.append(interface, property, value);
218
219 if (!bus.call(method))
220 {
221 log<level::ERR>("Failed to set property",
222 entry("PROPERTY=%s", property.c_str()),
223 entry("PATH=%s",objPath.c_str()),
224 entry("INTERFACE=%s",interface.c_str()));
225 elog<InternalFailure>();
226 }
227
228}
229
230
Tom Josephbe703f72017-03-09 12:34:35 +0530231std::string getService(sdbusplus::bus::bus& bus,
232 const std::string& intf,
233 const std::string& path)
234{
235 auto mapperCall = bus.new_method_call("xyz.openbmc_project.ObjectMapper",
Leonel Gonzalezd15e6c92017-03-16 13:47:58 -0500236 "/xyz/openbmc_project/object_mapper",
Tom Josephbe703f72017-03-09 12:34:35 +0530237 "xyz.openbmc_project.ObjectMapper",
238 "GetObject");
239
240 mapperCall.append(path);
241 mapperCall.append(std::vector<std::string>({intf}));
242
243 auto mapperResponseMsg = bus.call(mapperCall);
244
245 if (mapperResponseMsg.is_method_error())
246 {
247 throw std::runtime_error("ERROR in mapper call");
248 }
249
250 std::map<std::string, std::vector<std::string>> mapperResponse;
251 mapperResponseMsg.read(mapperResponse);
252
253 if (mapperResponse.begin() == mapperResponse.end())
254 {
255 throw std::runtime_error("ERROR in reading the mapper response");
256 }
257
258 return mapperResponse.begin()->first;
259}
260
Ratan Guptab8e99552017-07-27 07:07:48 +0530261ipmi::ObjectTree getAllDbusObjects(sdbusplus::bus::bus& bus,
262 const std::string& serviceRoot,
263 const std::string& interface,
264 const std::string& match)
265{
266 std::vector<std::string> interfaces;
267 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530268
Ratan Guptab8e99552017-07-27 07:07:48 +0530269 auto depth = 0;
270
271 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
272 MAPPER_OBJ,
273 MAPPER_INTF,
274 "GetSubTree");
275
276 mapperCall.append(serviceRoot, depth, interfaces);
277
278 auto mapperReply = bus.call(mapperCall);
279 if (mapperReply.is_method_error())
280 {
281 log<level::ERR>("Error in mapper call",
282 entry("SERVICEROOT=%s",serviceRoot.c_str()),
283 entry("INTERFACE=%s", interface.c_str()));
284
285 elog<InternalFailure>();
286 }
287
288 ObjectTree objectTree;
289 mapperReply.read(objectTree);
290
291 for (auto it = objectTree.begin(); it != objectTree.end();)
292 {
293 if (it->first.find(match) == std::string::npos)
294 {
295 it = objectTree.erase(it);
296 }
297 else
298 {
299 ++it;
300 }
301 }
302
303 return objectTree;
304}
305
306void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
307 const std::string& serviceRoot,
308 const std::string& interface,
309 const std::string& match)
310{
311 try
312 {
313 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
314
315 for (auto& object : objectTree)
316 {
317 method_no_args::callDbusMethod(bus,
318 object.second.begin()->first,
319 object.first,
320 DELETE_INTERFACE, "Delete");
321 }
322 }
323 catch (InternalFailure& e)
324 {
325 log<level::INFO>("Unable to delete the objects having",
326 entry("INTERFACE=%s", interface.c_str()),
327 entry("SERVICE=%s", serviceRoot.c_str()));
328 }
329}
330
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530331ObjectTree getAllAncestors(sdbusplus::bus::bus& bus,
332 const std::string& path,
333 InterfaceList&& interfaces)
334{
335 auto convertToString = [](InterfaceList& interfaces) -> std::string
336 {
337 std::string intfStr;
338 for (const auto& intf : interfaces)
339 {
340 intfStr += "," + intf;
341 }
342 return intfStr;
343 };
344
345 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
346 MAPPER_OBJ,
347 MAPPER_INTF,
348 "GetAncestors");
349 mapperCall.append(path, interfaces);
350
351 auto mapperReply = bus.call(mapperCall);
352 if (mapperReply.is_method_error())
353 {
354 log<level::ERR>("Error in mapper call",
355 entry("PATH=%s", path.c_str()),
356 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500357 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530358
359 elog<InternalFailure>();
360 }
361
362 ObjectTree objectTree;
363 mapperReply.read(objectTree);
364
365 if (objectTree.empty())
366 {
Patrick Venturef0c48782017-09-21 18:48:51 -0700367 log<level::ERR>("No Object has implemented the interface",
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530368 entry("PATH=%s", path.c_str()),
369 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500370 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530371 elog<InternalFailure>();
372 }
373
374 return objectTree;
375}
Ratan Guptab8e99552017-07-27 07:07:48 +0530376
377namespace method_no_args
378{
379
380void callDbusMethod(sdbusplus::bus::bus& bus,
381 const std::string& service,
382 const std::string& objPath,
383 const std::string& interface,
384 const std::string& method)
385
386{
387 auto busMethod = bus.new_method_call(
388 service.c_str(),
389 objPath.c_str(),
390 interface.c_str(),
391 method.c_str());
392
393 auto reply = bus.call(busMethod);
394
395 if (reply.is_method_error())
396 {
397 log<level::ERR>("Failed to execute method",
398 entry("METHOD=%s", method.c_str()),
399 entry("PATH=%s", objPath.c_str()),
400 entry("INTERFACE=%s", interface.c_str()));
401 elog<InternalFailure>();
402 }
403}
404
405}// namespace method_no_args
406
407namespace network
408{
409
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500410bool isLinkLocalIP(const std::string& address)
411{
412 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
413}
414
Ratan Guptab8e99552017-07-27 07:07:48 +0530415void createIP(sdbusplus::bus::bus& bus,
416 const std::string& service,
417 const std::string& objPath,
418 const std::string& protocolType,
419 const std::string& ipaddress,
420 uint8_t prefix)
421{
422 std::string gateway = "";
423
424 auto busMethod = bus.new_method_call(
425 service.c_str(),
426 objPath.c_str(),
427 IP_CREATE_INTERFACE,
428 "IP");
429
430 busMethod.append(protocolType, ipaddress, prefix, gateway);
431
432 auto reply = bus.call(busMethod);
433
434 if (reply.is_method_error())
435 {
436 log<level::ERR>("Failed to excute method",
437 entry("METHOD=%s", "IP"),
438 entry("PATH=%s", objPath.c_str()));
439 elog<InternalFailure>();
440 }
441
442}
443
Ratan Gupta533d03b2017-07-30 10:39:22 +0530444void createVLAN(sdbusplus::bus::bus& bus,
445 const std::string& service,
446 const std::string& objPath,
447 const std::string& interfaceName,
448 uint32_t vlanID)
449{
450 auto busMethod = bus.new_method_call(
451 service.c_str(),
452 objPath.c_str(),
453 VLAN_CREATE_INTERFACE,
454 "VLAN");
455
456 busMethod.append(interfaceName, vlanID);
457
458 auto reply = bus.call(busMethod);
459
460 if (reply.is_method_error())
461 {
462 log<level::ERR>("Failed to excute method",
463 entry("METHOD=%s", "VLAN"),
464 entry("PATH=%s", objPath.c_str()));
465 elog<InternalFailure>();
466 }
467
468}
469
Ratan Guptab8e99552017-07-27 07:07:48 +0530470uint8_t toPrefix(int addressFamily, const std::string& subnetMask)
471{
472 if (addressFamily == AF_INET6)
473 {
474 return 0;
475 }
476
477 uint32_t buff {};
478
479 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
480 if (rc <= 0)
481 {
482 log<level::ERR>("inet_pton failed:",
483 entry("SUBNETMASK=%s", subnetMask));
484 return 0;
485 }
486
487 buff = be32toh(buff);
488 // total no of bits - total no of leading zero == total no of ones
489 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
490 {
491 return __builtin_popcount(buff);
492 }
493 else
494 {
495 log<level::ERR>("Invalid Mask",
496 entry("SUBNETMASK=%s", subnetMask));
497 return 0;
498 }
499}
500
Ratan Gupta533d03b2017-07-30 10:39:22 +0530501uint32_t getVLAN(const std::string& path)
502{
503 // Path would be look like
504 // /xyz/openbmc_project/network/eth0_443/ipv4
505
506 uint32_t vlanID = 0;
507 try
508 {
509 auto intfObjectPath = path.substr(0,
510 path.find(IP_TYPE) - 1);
511
512 auto intfName = intfObjectPath.substr(intfObjectPath.rfind("/") + 1);
513
514 auto index = intfName.find("_");
515 if (index != std::string::npos)
516 {
517 auto str = intfName.substr(index + 1);
518 vlanID = std::stoul(str);
519 }
520 }
521 catch (std::exception & e)
522 {
Gunnar Mills8991dd62017-10-25 17:11:29 -0500523 log<level::ERR>("Exception occurred during getVLAN",
Ratan Gupta533d03b2017-07-30 10:39:22 +0530524 entry("PATH=%s",path.c_str()),
Gunnar Mills5b801e42017-10-19 17:11:42 -0500525 entry("EXCEPTION=%s", e.what()));
Ratan Gupta533d03b2017-07-30 10:39:22 +0530526 }
527 return vlanID;
528}
529
Ratan Guptab8e99552017-07-27 07:07:48 +0530530} // namespace network
Tom Josephbe703f72017-03-09 12:34:35 +0530531} // namespace ipmi