blob: 31bdd653648e74790cec9b61c1263904a8cb4fcc [file] [log] [blame]
Ratan Gupta56187e72017-08-13 09:40:14 +05301#include "config_parser.hpp"
Ratan Gupta3681a502017-06-17 19:20:04 +05302#include "util.hpp"
Ratan Gupta56187e72017-08-13 09:40:14 +05303#include "types.hpp"
Ratan Gupta11cef802017-05-29 08:41:48 +05304#include "xyz/openbmc_project/Common/error.hpp"
5
6#include <phosphor-logging/log.hpp>
7#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +05308
Ratan Gupta3681a502017-06-17 19:20:04 +05309#include <arpa/inet.h>
10#include <dirent.h>
11#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +053012#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053013
Ratan Gupta8804feb2017-05-25 10:49:57 +053014#include <iostream>
15#include <list>
16#include <string>
17#include <algorithm>
Ratan Gupta56187e72017-08-13 09:40:14 +053018#include <experimental/filesystem>
Ratan Gupta8804feb2017-05-25 10:49:57 +053019
20namespace phosphor
21{
22namespace network
23{
Ratan Guptabc886292017-07-25 18:29:57 +053024
Ratan Gupta8804feb2017-05-25 10:49:57 +053025namespace
26{
27
28using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053029using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053030namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053031
32uint8_t toV6Cidr(const std::string& subnetMask)
33{
34 uint8_t pos = 0;
35 uint8_t prevPos = 0;
36 uint8_t cidr = 0;
37 uint16_t buff {};
38 do
39 {
40 //subnet mask look like ffff:ffff::
41 // or ffff:c000::
42 pos = subnetMask.find(":", prevPos);
43 if (pos == std::string::npos)
44 {
45 break;
46 }
47
48 auto str = subnetMask.substr(prevPos, (pos - prevPos));
49 prevPos = pos + 1;
50
51 // String length is 0
52 if (!str.length())
53 {
54 return cidr;
55 }
56 //converts it into number.
57 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
58 {
59 log<level::ERR>("Invalid Mask",
Ratan Guptabc886292017-07-25 18:29:57 +053060 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +053061
62 return 0;
63 }
64
65 // convert the number into bitset
66 // and check for how many ones are there.
67 // if we don't have all the ones then make
68 // sure that all the ones should be left justify.
69
70 if (__builtin_popcount(buff) != 16)
71 {
72 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) != __builtin_popcount(buff))
73 {
74 log<level::ERR>("Invalid Mask",
75 entry("SUBNETMASK=%s", subnetMask));
76
77 return 0;
78 }
79 cidr += __builtin_popcount(buff);
80 return cidr;
81 }
82
83 cidr += 16;
84 }
85 while (1);
86
87 return cidr;
88}
89}// anonymous namespace
90
91uint8_t toCidr(int addressFamily, const std::string& subnetMask)
92{
93 if (addressFamily == AF_INET6)
94 {
95 return toV6Cidr(subnetMask);
96 }
97
98 uint32_t buff;
99
100 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
101 if (rc <= 0)
102 {
103 log<level::ERR>("inet_pton failed:",
Ratan Gupta11cef802017-05-29 08:41:48 +0530104 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530105 return 0;
106 }
107
108 buff = be32toh(buff);
109 // total no of bits - total no of leading zero == total no of ones
110 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
111 {
112 return __builtin_popcount(buff);
113 }
114 else
115 {
116 log<level::ERR>("Invalid Mask",
Ratan Gupta11cef802017-05-29 08:41:48 +0530117 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530118 return 0;
119 }
120}
121
122std::string toMask(int addressFamily, uint8_t prefix)
123{
124 if (addressFamily == AF_INET6)
125 {
126 //TODO:- conversion for v6
127 return "";
128 }
129
130 if (prefix < 1 || prefix > 30)
131 {
132 log<level::ERR>("Invalid Prefix",
133 entry("PREFIX=%d", prefix));
134 return "";
135 }
136 /* Create the netmask from the number of bits */
137 unsigned long mask = 0;
138 for (auto i = 0 ; i < prefix ; i++)
139 {
140 mask |= 1 << (31 - i);
141 }
142 struct in_addr netmask;
143 netmask.s_addr = htonl(mask);
144 return inet_ntoa(netmask);
145}
146
Ratan Gupta11cef802017-05-29 08:41:48 +0530147std::string getNetworkID(int addressFamily, const std::string& ipaddress,
Ratan Guptabc886292017-07-25 18:29:57 +0530148 uint8_t prefix)
Ratan Gupta11cef802017-05-29 08:41:48 +0530149{
150 unsigned char* pntMask = nullptr;
151 unsigned char* pntNetwork = nullptr;
152 int bit {};
153 int offset {};
154 struct in6_addr netmask {};
155 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
156 0xf8, 0xfc, 0xfe, 0xff
157 };
158
159 pntMask = reinterpret_cast<unsigned char*>(&netmask);
160
161 offset = prefix / 8;
162 bit = prefix % 8;
163
164 while (offset--)
165 {
166 *pntMask++ = 0xff;
167 }
168
169 if (bit)
170 {
171 *pntMask = maskbit[bit];
172 }
173
174 // convert ipaddres string into network address
175 struct in6_addr ipaddressNetwork;
176 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
177 {
178 log<level::ERR>("inet_pton failure",
Ratan Guptabc886292017-07-25 18:29:57 +0530179 entry("IPADDRESS=%s", ipaddress.c_str()));
Ratan Gupta11cef802017-05-29 08:41:48 +0530180 report<InternalFailure>();
181
182 return "";
183 }
184
185 // Now bit wise and gets you the network address
186 pntMask = reinterpret_cast<unsigned char*>(&netmask);
187 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
188
189 for (int i = 0; i < 16 ; i++)
190 {
191 pntNetwork[i] = pntNetwork[i] & pntMask[i];
192 }
193
194 //convert the network address into string fomat.
195 char networkString[INET6_ADDRSTRLEN] = { 0 };
196 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
197 INET6_ADDRSTRLEN) == NULL)
198 {
199 log<level::ERR>("inet_ntop failure");
200 report<InternalFailure>();
201 }
202 return networkString;
203}
204
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500205bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530206{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500207 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
208}
209
210bool isValidIP(int addressFamily, const std::string& address)
211{
212 unsigned char buf[sizeof(struct in6_addr)];
213
214 return inet_pton(addressFamily, address.c_str(), buf) > 0;
215}
216
217bool isValidPrefix(int addressFamily, uint8_t prefixLength)
218{
219 if (addressFamily == AF_INET)
220 {
221 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
222 prefixLength > IPV4_MAX_PREFIX_LENGTH)
223 {
224 return false;
225 }
226 }
227
228 if (addressFamily == AF_INET6)
229 {
230 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
231 prefixLength > IPV6_MAX_PREFIX_LENGTH)
232 {
233 return false;
234 }
235 }
236
237 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530238}
239
Ratan Gupta3681a502017-06-17 19:20:04 +0530240IntfAddrMap getInterfaceAddrs()
241{
Ratan Guptabc886292017-07-25 18:29:57 +0530242 IntfAddrMap intfMap {};
243 AddrList addrList {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530244 struct ifaddrs* ifaddr = nullptr;
245
246 // attempt to fill struct with ifaddrs
247 if (getifaddrs(&ifaddr) == -1)
248 {
249 auto error = errno;
250 log<level::ERR>("Error occurred during the getifaddrs call",
251 entry("ERRNO=%s", strerror(error)));
252 elog<InternalFailure>();
253 }
254
255 AddrPtr ifaddrPtr(ifaddr);
256 ifaddr = nullptr;
257
Ratan Guptabc886292017-07-25 18:29:57 +0530258 std::string intfName {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530259
260 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
261 {
262 // walk interfaces
263 if (ifa->ifa_addr == nullptr)
264 {
265 continue;
266 }
267
268 // get only INET interfaces not ipv6
269 if (ifa->ifa_addr->sa_family == AF_INET ||
270 ifa->ifa_addr->sa_family == AF_INET6)
271 {
272 // if loopback, or not running ignore
273 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
274 !(ifa->ifa_flags & IFF_RUNNING))
275 {
276 continue;
277 }
278 // if the interface name is not same as the previous
279 // iteration then add the addr list into
280 // the map.
281 if (intfName != "" && intfName != std::string(ifa->ifa_name))
282 {
283 intfMap.emplace(intfName, addrList);
284 addrList.clear();
285 }
286 intfName = ifa->ifa_name;
Ratan Guptabc886292017-07-25 18:29:57 +0530287 AddrInfo info {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530288 char ip[INET6_ADDRSTRLEN] = { 0 };
289 char subnetMask[INET6_ADDRSTRLEN] = { 0 };
290
291 if (ifa->ifa_addr->sa_family == AF_INET)
292 {
293
294 inet_ntop(ifa->ifa_addr->sa_family,
295 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
296 ip,
297 sizeof(ip));
298
299 inet_ntop(ifa->ifa_addr->sa_family,
300 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
301 subnetMask,
302 sizeof(subnetMask));
303
304 }
305 else
306 {
307 inet_ntop(ifa->ifa_addr->sa_family,
308 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
309 ip,
310 sizeof(ip));
311
312 inet_ntop(ifa->ifa_addr->sa_family,
313 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
314 subnetMask,
315 sizeof(subnetMask));
316
317 }
318
319 info.addrType = ifa->ifa_addr->sa_family;
320 info.ipaddress = ip;
321 info.prefix = toCidr(info.addrType, std::string(subnetMask));
322 addrList.emplace_back(info);
323 }
324 }
325 intfMap.emplace(intfName, addrList);
326 return intfMap;
327}
328
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530329InterfaceList getInterfaces()
330{
331 InterfaceList interfaces {};
332 struct ifaddrs* ifaddr = nullptr;
333
334 // attempt to fill struct with ifaddrs
335 if (getifaddrs(&ifaddr) == -1)
336 {
337 auto error = errno;
338 log<level::ERR>("Error occurred during the getifaddrs call",
339 entry("ERRNO=%d", error));
340 elog<InternalFailure>();
341 }
342
343 AddrPtr ifaddrPtr(ifaddr);
344 ifaddr = nullptr;
345
346 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
347 {
348 // walk interfaces
349 // if loopback, or not running ignore
350 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
351 !(ifa->ifa_flags & IFF_RUNNING))
352 {
353 continue;
354 }
355 interfaces.emplace(ifa->ifa_name);
356 }
357 return interfaces;
358}
359
360
Ratan Guptabc886292017-07-25 18:29:57 +0530361void deleteInterface(const std::string& intf)
362{
363 pid_t pid = fork();
364 int status {};
365
366 if (pid == 0)
367 {
368
369 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
370 auto error = errno;
371 log<level::ERR>("Couldn't delete the device",
372 entry("ERRNO=%d", error),
373 entry("INTF=%s", intf.c_str()));
374 elog<InternalFailure>();
375 }
376 else if (pid < 0)
377 {
378 auto error = errno;
379 log<level::ERR>("Error occurred during fork",
380 entry("ERRNO=%d", error));
381 elog<InternalFailure>();
382 }
383 else if (pid > 0)
384 {
385 while (waitpid(pid, &status, 0) == -1)
386 {
387 if (errno != EINTR)
388 { /* Error other than EINTR */
389 status = -1;
390 break;
391 }
392 }
393
394 if(status < 0)
395 {
396 log<level::ERR>("Unable to delete the interface",
397 entry("INTF=%s", intf.c_str(),
398 entry("STATUS=%d", status)));
399 elog<InternalFailure>();
400 }
401 }
402}
403
Ratan Gupta56187e72017-08-13 09:40:14 +0530404bool getDHCPValue(const std::string& confDir, const std::string& intf)
405{
406 bool dhcp = false;
407 // Get the interface mode value from systemd conf
408 //using namespace std::string_literals;
409 fs::path confPath = confDir;
410 std::string fileName = systemd::config::networkFilePrefix + intf +
411 systemd::config::networkFileSuffix;
412 confPath /= fileName;
413
414 try
415 {
416 config::Parser parser(confPath.string());
417 auto values = parser.getValues("Network", "DHCP");
418 // There will be only single value for DHCP key.
419 if (values[0] == "true")
420 {
421 dhcp = true;
422 }
423 }
424 catch (InternalFailure& e)
425 {
Ratan Guptabd303b12017-08-18 17:10:07 +0530426 log<level::INFO>("Exception occured during getting of DHCP value");
Ratan Gupta56187e72017-08-13 09:40:14 +0530427 }
428 return dhcp;
429}
430
Ratan Guptabd303b12017-08-18 17:10:07 +0530431namespace internal
432{
Ratan Gupta56187e72017-08-13 09:40:14 +0530433
Ratan Guptabd303b12017-08-18 17:10:07 +0530434void executeCommandinChildProcess(const char* path, char** args)
435{
436 using namespace std::string_literals;
437 pid_t pid = fork();
438 int status {};
439
440 if (pid == 0)
441 {
442 execv(path, args);
443 auto error = errno;
444 // create the command from var args.
445 std::string command = path + " "s;
446
447 for(int i = 0; args[i]; i++)
448 {
449 command += args[i] + " "s;
450 }
451
452 log<level::ERR>("Couldn't exceute the command",
453 entry("ERRNO=%d", error),
454 entry("CMD=%s", command.c_str()));
455 elog<InternalFailure>();
456 }
457 else if (pid < 0)
458 {
459 auto error = errno;
460 log<level::ERR>("Error occurred during fork",
461 entry("ERRNO=%d", error));
462 elog<InternalFailure>();
463 }
464 else if (pid > 0)
465 {
466 while (waitpid(pid, &status, 0) == -1)
467 {
468 if (errno != EINTR)
469 { //Error other than EINTR
470 status = -1;
471 break;
472 }
473 }
474
475 if(status < 0)
476 {
477 std::string command = path + " "s;
478 for(int i = 0; args[i]; i++)
479 {
480 command += args[i] + " "s;
481 }
482
483 log<level::ERR>("Unable to execute the command",
484 entry("CMD=%s", command.c_str(),
485 entry("STATUS=%d", status)));
486 elog<InternalFailure>();
487 }
488 }
489
490}
491} //namespace internal
492
493namespace mac_address
494{
495
496constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
497constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
498constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
499constexpr auto propIntf = "org.freedesktop.DBus.Properties";
500constexpr auto methodGet = "Get";
501
502using DbusObjectPath = std::string;
503using DbusService = std::string;
504using DbusInterface = std::string;
505using ObjectTree = std::map<DbusObjectPath,
506 std::map<DbusService, std::vector<DbusInterface>>>;
507
508constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
509constexpr auto invNetworkIntf =
510 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
511constexpr auto invRoot = "/xyz/openbmc_project/inventory";
512
513std::string getfromInventory(sdbusplus::bus::bus& bus)
514{
515 std::vector<DbusInterface> interfaces;
516 interfaces.emplace_back(invNetworkIntf);
517
518 auto depth = 0;
519
520 auto mapperCall = bus.new_method_call(mapperBus,
521 mapperObj,
522 mapperIntf,
523 "GetSubTree");
524
525 mapperCall.append(invRoot, depth, interfaces);
526
527 auto mapperReply = bus.call(mapperCall);
528 if (mapperReply.is_method_error())
529 {
530 log<level::ERR>("Error in mapper call");
531 elog<InternalFailure>();
532 }
533
534 ObjectTree objectTree;
535 mapperReply.read(objectTree);
536
537 if (objectTree.empty())
538 {
539 log<level::ERR>("No Object has implemented the interface",
540 entry("INTERFACE=%s", invNetworkIntf));
541 elog<InternalFailure>();
542 }
543
Gunnar Millsa251a782017-09-26 16:49:08 -0500544 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530545
546 auto objPath = objectTree.begin()->first;
547 auto service = objectTree.begin()->second.begin()->first;
548
549 sdbusplus::message::variant<std::string> value;
550
551 auto method = bus.new_method_call(
552 service.c_str(),
553 objPath.c_str(),
554 propIntf,
555 methodGet);
556
557 method.append(invNetworkIntf, "MACAddress");
558
559 auto reply = bus.call(method);
560 if (reply.is_method_error())
561 {
562 log<level::ERR>("Failed to get MACAddress",
563 entry("PATH=%s", objPath.c_str()),
564 entry("INTERFACE=%s", invNetworkIntf));
565 elog<InternalFailure>();
566 }
567
568 reply.read(value);
569 return value.get<std::string>();
570}
571
572}//namespace mac_address
Ratan Gupta8804feb2017-05-25 10:49:57 +0530573}//namespace network
574}//namespace phosphor