blob: fa6bd04677ee3524baa736a6b4554ce4cf240d36 [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
Ratan Gupta01d4bd12017-08-07 15:53:25 +0530201void setDbusProperty(sdbusplus::bus::bus& bus,
202 const std::string& service,
Ratan Guptacc8feb42017-07-25 21:52:10 +0530203 const std::string& objPath,
204 const std::string& interface,
205 const std::string& property,
206 const Value& value)
207{
Ratan Guptacc8feb42017-07-25 21:52:10 +0530208 auto method = bus.new_method_call(
209 service.c_str(),
210 objPath.c_str(),
211 PROP_INTF,
212 METHOD_SET);
213
214 method.append(interface, property, value);
215
216 if (!bus.call(method))
217 {
218 log<level::ERR>("Failed to set property",
219 entry("PROPERTY=%s", property.c_str()),
220 entry("PATH=%s",objPath.c_str()),
221 entry("INTERFACE=%s",interface.c_str()));
222 elog<InternalFailure>();
223 }
224
225}
226
227
Tom Josephbe703f72017-03-09 12:34:35 +0530228std::string getService(sdbusplus::bus::bus& bus,
229 const std::string& intf,
230 const std::string& path)
231{
232 auto mapperCall = bus.new_method_call("xyz.openbmc_project.ObjectMapper",
Leonel Gonzalezd15e6c92017-03-16 13:47:58 -0500233 "/xyz/openbmc_project/object_mapper",
Tom Josephbe703f72017-03-09 12:34:35 +0530234 "xyz.openbmc_project.ObjectMapper",
235 "GetObject");
236
237 mapperCall.append(path);
238 mapperCall.append(std::vector<std::string>({intf}));
239
240 auto mapperResponseMsg = bus.call(mapperCall);
241
242 if (mapperResponseMsg.is_method_error())
243 {
244 throw std::runtime_error("ERROR in mapper call");
245 }
246
247 std::map<std::string, std::vector<std::string>> mapperResponse;
248 mapperResponseMsg.read(mapperResponse);
249
250 if (mapperResponse.begin() == mapperResponse.end())
251 {
252 throw std::runtime_error("ERROR in reading the mapper response");
253 }
254
255 return mapperResponse.begin()->first;
256}
257
Ratan Guptab8e99552017-07-27 07:07:48 +0530258ipmi::ObjectTree getAllDbusObjects(sdbusplus::bus::bus& bus,
259 const std::string& serviceRoot,
260 const std::string& interface,
261 const std::string& match)
262{
263 std::vector<std::string> interfaces;
264 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530265
Ratan Guptab8e99552017-07-27 07:07:48 +0530266 auto depth = 0;
267
268 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
269 MAPPER_OBJ,
270 MAPPER_INTF,
271 "GetSubTree");
272
273 mapperCall.append(serviceRoot, depth, interfaces);
274
275 auto mapperReply = bus.call(mapperCall);
276 if (mapperReply.is_method_error())
277 {
278 log<level::ERR>("Error in mapper call",
279 entry("SERVICEROOT=%s",serviceRoot.c_str()),
280 entry("INTERFACE=%s", interface.c_str()));
281
282 elog<InternalFailure>();
283 }
284
285 ObjectTree objectTree;
286 mapperReply.read(objectTree);
287
288 for (auto it = objectTree.begin(); it != objectTree.end();)
289 {
290 if (it->first.find(match) == std::string::npos)
291 {
292 it = objectTree.erase(it);
293 }
294 else
295 {
296 ++it;
297 }
298 }
299
300 return objectTree;
301}
302
303void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
304 const std::string& serviceRoot,
305 const std::string& interface,
306 const std::string& match)
307{
308 try
309 {
310 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
311
312 for (auto& object : objectTree)
313 {
314 method_no_args::callDbusMethod(bus,
315 object.second.begin()->first,
316 object.first,
317 DELETE_INTERFACE, "Delete");
318 }
319 }
320 catch (InternalFailure& e)
321 {
322 log<level::INFO>("Unable to delete the objects having",
323 entry("INTERFACE=%s", interface.c_str()),
324 entry("SERVICE=%s", serviceRoot.c_str()));
325 }
326}
327
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530328ObjectTree getAllAncestors(sdbusplus::bus::bus& bus,
329 const std::string& path,
330 InterfaceList&& interfaces)
331{
332 auto convertToString = [](InterfaceList& interfaces) -> std::string
333 {
334 std::string intfStr;
335 for (const auto& intf : interfaces)
336 {
337 intfStr += "," + intf;
338 }
339 return intfStr;
340 };
341
342 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
343 MAPPER_OBJ,
344 MAPPER_INTF,
345 "GetAncestors");
346 mapperCall.append(path, interfaces);
347
348 auto mapperReply = bus.call(mapperCall);
349 if (mapperReply.is_method_error())
350 {
351 log<level::ERR>("Error in mapper call",
352 entry("PATH=%s", path.c_str()),
353 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500354 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530355
356 elog<InternalFailure>();
357 }
358
359 ObjectTree objectTree;
360 mapperReply.read(objectTree);
361
362 if (objectTree.empty())
363 {
Patrick Venturef0c48782017-09-21 18:48:51 -0700364 log<level::ERR>("No Object has implemented the interface",
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530365 entry("PATH=%s", path.c_str()),
366 entry("INTERFACES=%s",
Gunnar Mills5b801e42017-10-19 17:11:42 -0500367 convertToString(interfaces).c_str()));
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530368 elog<InternalFailure>();
369 }
370
371 return objectTree;
372}
Ratan Guptab8e99552017-07-27 07:07:48 +0530373
374namespace method_no_args
375{
376
377void callDbusMethod(sdbusplus::bus::bus& bus,
378 const std::string& service,
379 const std::string& objPath,
380 const std::string& interface,
381 const std::string& method)
382
383{
384 auto busMethod = bus.new_method_call(
385 service.c_str(),
386 objPath.c_str(),
387 interface.c_str(),
388 method.c_str());
389
390 auto reply = bus.call(busMethod);
391
392 if (reply.is_method_error())
393 {
394 log<level::ERR>("Failed to execute method",
395 entry("METHOD=%s", method.c_str()),
396 entry("PATH=%s", objPath.c_str()),
397 entry("INTERFACE=%s", interface.c_str()));
398 elog<InternalFailure>();
399 }
400}
401
402}// namespace method_no_args
403
404namespace network
405{
406
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -0500407bool isLinkLocalIP(const std::string& address)
408{
409 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
410}
411
Ratan Guptab8e99552017-07-27 07:07:48 +0530412void createIP(sdbusplus::bus::bus& bus,
413 const std::string& service,
414 const std::string& objPath,
415 const std::string& protocolType,
416 const std::string& ipaddress,
417 uint8_t prefix)
418{
419 std::string gateway = "";
420
421 auto busMethod = bus.new_method_call(
422 service.c_str(),
423 objPath.c_str(),
424 IP_CREATE_INTERFACE,
425 "IP");
426
427 busMethod.append(protocolType, ipaddress, prefix, gateway);
428
429 auto reply = bus.call(busMethod);
430
431 if (reply.is_method_error())
432 {
433 log<level::ERR>("Failed to excute method",
434 entry("METHOD=%s", "IP"),
435 entry("PATH=%s", objPath.c_str()));
436 elog<InternalFailure>();
437 }
438
439}
440
Ratan Gupta533d03b2017-07-30 10:39:22 +0530441void createVLAN(sdbusplus::bus::bus& bus,
442 const std::string& service,
443 const std::string& objPath,
444 const std::string& interfaceName,
445 uint32_t vlanID)
446{
447 auto busMethod = bus.new_method_call(
448 service.c_str(),
449 objPath.c_str(),
450 VLAN_CREATE_INTERFACE,
451 "VLAN");
452
453 busMethod.append(interfaceName, vlanID);
454
455 auto reply = bus.call(busMethod);
456
457 if (reply.is_method_error())
458 {
459 log<level::ERR>("Failed to excute method",
460 entry("METHOD=%s", "VLAN"),
461 entry("PATH=%s", objPath.c_str()));
462 elog<InternalFailure>();
463 }
464
465}
466
Ratan Guptab8e99552017-07-27 07:07:48 +0530467uint8_t toPrefix(int addressFamily, const std::string& subnetMask)
468{
469 if (addressFamily == AF_INET6)
470 {
471 return 0;
472 }
473
474 uint32_t buff {};
475
476 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
477 if (rc <= 0)
478 {
479 log<level::ERR>("inet_pton failed:",
480 entry("SUBNETMASK=%s", subnetMask));
481 return 0;
482 }
483
484 buff = be32toh(buff);
485 // total no of bits - total no of leading zero == total no of ones
486 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
487 {
488 return __builtin_popcount(buff);
489 }
490 else
491 {
492 log<level::ERR>("Invalid Mask",
493 entry("SUBNETMASK=%s", subnetMask));
494 return 0;
495 }
496}
497
Ratan Gupta533d03b2017-07-30 10:39:22 +0530498uint32_t getVLAN(const std::string& path)
499{
500 // Path would be look like
501 // /xyz/openbmc_project/network/eth0_443/ipv4
502
503 uint32_t vlanID = 0;
504 try
505 {
506 auto intfObjectPath = path.substr(0,
507 path.find(IP_TYPE) - 1);
508
509 auto intfName = intfObjectPath.substr(intfObjectPath.rfind("/") + 1);
510
511 auto index = intfName.find("_");
512 if (index != std::string::npos)
513 {
514 auto str = intfName.substr(index + 1);
515 vlanID = std::stoul(str);
516 }
517 }
518 catch (std::exception & e)
519 {
Gunnar Mills8991dd62017-10-25 17:11:29 -0500520 log<level::ERR>("Exception occurred during getVLAN",
Ratan Gupta533d03b2017-07-30 10:39:22 +0530521 entry("PATH=%s",path.c_str()),
Gunnar Mills5b801e42017-10-19 17:11:42 -0500522 entry("EXCEPTION=%s", e.what()));
Ratan Gupta533d03b2017-07-30 10:39:22 +0530523 }
524 return vlanID;
525}
526
Ratan Guptab8e99552017-07-27 07:07:48 +0530527} // namespace network
Tom Josephbe703f72017-03-09 12:34:35 +0530528} // namespace ipmi