blob: 48b5fcb5fe42ad20c5090c2589d0193d8c6ce215 [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
Ratan Gupta8804feb2017-05-25 10:49:57 +0530205bool isLinkLocal(const std::string& address)
206{
207 std::string linklocal = "fe80";
208 return std::mismatch(linklocal.begin(), linklocal.end(),
209 address.begin()).first == linklocal.end() ?
Ratan Guptabc886292017-07-25 18:29:57 +0530210 true : false;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530211}
212
Ratan Gupta3681a502017-06-17 19:20:04 +0530213IntfAddrMap getInterfaceAddrs()
214{
Ratan Guptabc886292017-07-25 18:29:57 +0530215 IntfAddrMap intfMap {};
216 AddrList addrList {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530217 struct ifaddrs* ifaddr = nullptr;
218
219 // attempt to fill struct with ifaddrs
220 if (getifaddrs(&ifaddr) == -1)
221 {
222 auto error = errno;
223 log<level::ERR>("Error occurred during the getifaddrs call",
224 entry("ERRNO=%s", strerror(error)));
225 elog<InternalFailure>();
226 }
227
228 AddrPtr ifaddrPtr(ifaddr);
229 ifaddr = nullptr;
230
Ratan Guptabc886292017-07-25 18:29:57 +0530231 std::string intfName {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530232
233 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
234 {
235 // walk interfaces
236 if (ifa->ifa_addr == nullptr)
237 {
238 continue;
239 }
240
241 // get only INET interfaces not ipv6
242 if (ifa->ifa_addr->sa_family == AF_INET ||
243 ifa->ifa_addr->sa_family == AF_INET6)
244 {
245 // if loopback, or not running ignore
246 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
247 !(ifa->ifa_flags & IFF_RUNNING))
248 {
249 continue;
250 }
251 // if the interface name is not same as the previous
252 // iteration then add the addr list into
253 // the map.
254 if (intfName != "" && intfName != std::string(ifa->ifa_name))
255 {
256 intfMap.emplace(intfName, addrList);
257 addrList.clear();
258 }
259 intfName = ifa->ifa_name;
Ratan Guptabc886292017-07-25 18:29:57 +0530260 AddrInfo info {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530261 char ip[INET6_ADDRSTRLEN] = { 0 };
262 char subnetMask[INET6_ADDRSTRLEN] = { 0 };
263
264 if (ifa->ifa_addr->sa_family == AF_INET)
265 {
266
267 inet_ntop(ifa->ifa_addr->sa_family,
268 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
269 ip,
270 sizeof(ip));
271
272 inet_ntop(ifa->ifa_addr->sa_family,
273 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
274 subnetMask,
275 sizeof(subnetMask));
276
277 }
278 else
279 {
280 inet_ntop(ifa->ifa_addr->sa_family,
281 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
282 ip,
283 sizeof(ip));
284
285 inet_ntop(ifa->ifa_addr->sa_family,
286 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
287 subnetMask,
288 sizeof(subnetMask));
289
290 }
291
292 info.addrType = ifa->ifa_addr->sa_family;
293 info.ipaddress = ip;
294 info.prefix = toCidr(info.addrType, std::string(subnetMask));
295 addrList.emplace_back(info);
296 }
297 }
298 intfMap.emplace(intfName, addrList);
299 return intfMap;
300}
301
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530302InterfaceList getInterfaces()
303{
304 InterfaceList interfaces {};
305 struct ifaddrs* ifaddr = nullptr;
306
307 // attempt to fill struct with ifaddrs
308 if (getifaddrs(&ifaddr) == -1)
309 {
310 auto error = errno;
311 log<level::ERR>("Error occurred during the getifaddrs call",
312 entry("ERRNO=%d", error));
313 elog<InternalFailure>();
314 }
315
316 AddrPtr ifaddrPtr(ifaddr);
317 ifaddr = nullptr;
318
319 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
320 {
321 // walk interfaces
322 // if loopback, or not running ignore
323 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
324 !(ifa->ifa_flags & IFF_RUNNING))
325 {
326 continue;
327 }
328 interfaces.emplace(ifa->ifa_name);
329 }
330 return interfaces;
331}
332
333
Ratan Guptabc886292017-07-25 18:29:57 +0530334void deleteInterface(const std::string& intf)
335{
336 pid_t pid = fork();
337 int status {};
338
339 if (pid == 0)
340 {
341
342 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
343 auto error = errno;
344 log<level::ERR>("Couldn't delete the device",
345 entry("ERRNO=%d", error),
346 entry("INTF=%s", intf.c_str()));
347 elog<InternalFailure>();
348 }
349 else if (pid < 0)
350 {
351 auto error = errno;
352 log<level::ERR>("Error occurred during fork",
353 entry("ERRNO=%d", error));
354 elog<InternalFailure>();
355 }
356 else if (pid > 0)
357 {
358 while (waitpid(pid, &status, 0) == -1)
359 {
360 if (errno != EINTR)
361 { /* Error other than EINTR */
362 status = -1;
363 break;
364 }
365 }
366
367 if(status < 0)
368 {
369 log<level::ERR>("Unable to delete the interface",
370 entry("INTF=%s", intf.c_str(),
371 entry("STATUS=%d", status)));
372 elog<InternalFailure>();
373 }
374 }
375}
376
Ratan Gupta56187e72017-08-13 09:40:14 +0530377bool getDHCPValue(const std::string& confDir, const std::string& intf)
378{
379 bool dhcp = false;
380 // Get the interface mode value from systemd conf
381 //using namespace std::string_literals;
382 fs::path confPath = confDir;
383 std::string fileName = systemd::config::networkFilePrefix + intf +
384 systemd::config::networkFileSuffix;
385 confPath /= fileName;
386
387 try
388 {
389 config::Parser parser(confPath.string());
390 auto values = parser.getValues("Network", "DHCP");
391 // There will be only single value for DHCP key.
392 if (values[0] == "true")
393 {
394 dhcp = true;
395 }
396 }
397 catch (InternalFailure& e)
398 {
Ratan Guptabd303b12017-08-18 17:10:07 +0530399 log<level::INFO>("Exception occured during getting of DHCP value");
Ratan Gupta56187e72017-08-13 09:40:14 +0530400 }
401 return dhcp;
402}
403
Ratan Guptabd303b12017-08-18 17:10:07 +0530404namespace internal
405{
Ratan Gupta56187e72017-08-13 09:40:14 +0530406
Ratan Guptabd303b12017-08-18 17:10:07 +0530407void executeCommandinChildProcess(const char* path, char** args)
408{
409 using namespace std::string_literals;
410 pid_t pid = fork();
411 int status {};
412
413 if (pid == 0)
414 {
415 execv(path, args);
416 auto error = errno;
417 // create the command from var args.
418 std::string command = path + " "s;
419
420 for(int i = 0; args[i]; i++)
421 {
422 command += args[i] + " "s;
423 }
424
425 log<level::ERR>("Couldn't exceute the command",
426 entry("ERRNO=%d", error),
427 entry("CMD=%s", command.c_str()));
428 elog<InternalFailure>();
429 }
430 else if (pid < 0)
431 {
432 auto error = errno;
433 log<level::ERR>("Error occurred during fork",
434 entry("ERRNO=%d", error));
435 elog<InternalFailure>();
436 }
437 else if (pid > 0)
438 {
439 while (waitpid(pid, &status, 0) == -1)
440 {
441 if (errno != EINTR)
442 { //Error other than EINTR
443 status = -1;
444 break;
445 }
446 }
447
448 if(status < 0)
449 {
450 std::string command = path + " "s;
451 for(int i = 0; args[i]; i++)
452 {
453 command += args[i] + " "s;
454 }
455
456 log<level::ERR>("Unable to execute the command",
457 entry("CMD=%s", command.c_str(),
458 entry("STATUS=%d", status)));
459 elog<InternalFailure>();
460 }
461 }
462
463}
464} //namespace internal
465
466namespace mac_address
467{
468
469constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
470constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
471constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
472constexpr auto propIntf = "org.freedesktop.DBus.Properties";
473constexpr auto methodGet = "Get";
474
475using DbusObjectPath = std::string;
476using DbusService = std::string;
477using DbusInterface = std::string;
478using ObjectTree = std::map<DbusObjectPath,
479 std::map<DbusService, std::vector<DbusInterface>>>;
480
481constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
482constexpr auto invNetworkIntf =
483 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
484constexpr auto invRoot = "/xyz/openbmc_project/inventory";
485
486std::string getfromInventory(sdbusplus::bus::bus& bus)
487{
488 std::vector<DbusInterface> interfaces;
489 interfaces.emplace_back(invNetworkIntf);
490
491 auto depth = 0;
492
493 auto mapperCall = bus.new_method_call(mapperBus,
494 mapperObj,
495 mapperIntf,
496 "GetSubTree");
497
498 mapperCall.append(invRoot, depth, interfaces);
499
500 auto mapperReply = bus.call(mapperCall);
501 if (mapperReply.is_method_error())
502 {
503 log<level::ERR>("Error in mapper call");
504 elog<InternalFailure>();
505 }
506
507 ObjectTree objectTree;
508 mapperReply.read(objectTree);
509
510 if (objectTree.empty())
511 {
512 log<level::ERR>("No Object has implemented the interface",
513 entry("INTERFACE=%s", invNetworkIntf));
514 elog<InternalFailure>();
515 }
516
Gunnar Millsa251a782017-09-26 16:49:08 -0500517 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530518
519 auto objPath = objectTree.begin()->first;
520 auto service = objectTree.begin()->second.begin()->first;
521
522 sdbusplus::message::variant<std::string> value;
523
524 auto method = bus.new_method_call(
525 service.c_str(),
526 objPath.c_str(),
527 propIntf,
528 methodGet);
529
530 method.append(invNetworkIntf, "MACAddress");
531
532 auto reply = bus.call(method);
533 if (reply.is_method_error())
534 {
535 log<level::ERR>("Failed to get MACAddress",
536 entry("PATH=%s", objPath.c_str()),
537 entry("INTERFACE=%s", invNetworkIntf));
538 elog<InternalFailure>();
539 }
540
541 reply.read(value);
542 return value.get<std::string>();
543}
544
545}//namespace mac_address
Ratan Gupta8804feb2017-05-25 10:49:57 +0530546}//namespace network
547}//namespace phosphor