blob: 679b2cb2c7c9efe51fe24f6456531c948e30fad4 [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 Guptabc886292017-07-25 18:29:57 +0530302void deleteInterface(const std::string& intf)
303{
304 pid_t pid = fork();
305 int status {};
306
307 if (pid == 0)
308 {
309
310 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
311 auto error = errno;
312 log<level::ERR>("Couldn't delete the device",
313 entry("ERRNO=%d", error),
314 entry("INTF=%s", intf.c_str()));
315 elog<InternalFailure>();
316 }
317 else if (pid < 0)
318 {
319 auto error = errno;
320 log<level::ERR>("Error occurred during fork",
321 entry("ERRNO=%d", error));
322 elog<InternalFailure>();
323 }
324 else if (pid > 0)
325 {
326 while (waitpid(pid, &status, 0) == -1)
327 {
328 if (errno != EINTR)
329 { /* Error other than EINTR */
330 status = -1;
331 break;
332 }
333 }
334
335 if(status < 0)
336 {
337 log<level::ERR>("Unable to delete the interface",
338 entry("INTF=%s", intf.c_str(),
339 entry("STATUS=%d", status)));
340 elog<InternalFailure>();
341 }
342 }
343}
344
Ratan Gupta56187e72017-08-13 09:40:14 +0530345bool getDHCPValue(const std::string& confDir, const std::string& intf)
346{
347 bool dhcp = false;
348 // Get the interface mode value from systemd conf
349 //using namespace std::string_literals;
350 fs::path confPath = confDir;
351 std::string fileName = systemd::config::networkFilePrefix + intf +
352 systemd::config::networkFileSuffix;
353 confPath /= fileName;
354
355 try
356 {
357 config::Parser parser(confPath.string());
358 auto values = parser.getValues("Network", "DHCP");
359 // There will be only single value for DHCP key.
360 if (values[0] == "true")
361 {
362 dhcp = true;
363 }
364 }
365 catch (InternalFailure& e)
366 {
Ratan Guptabd303b12017-08-18 17:10:07 +0530367 log<level::INFO>("Exception occured during getting of DHCP value");
Ratan Gupta56187e72017-08-13 09:40:14 +0530368 }
369 return dhcp;
370}
371
Ratan Guptabd303b12017-08-18 17:10:07 +0530372namespace internal
373{
Ratan Gupta56187e72017-08-13 09:40:14 +0530374
Ratan Guptabd303b12017-08-18 17:10:07 +0530375void executeCommandinChildProcess(const char* path, char** args)
376{
377 using namespace std::string_literals;
378 pid_t pid = fork();
379 int status {};
380
381 if (pid == 0)
382 {
383 execv(path, args);
384 auto error = errno;
385 // create the command from var args.
386 std::string command = path + " "s;
387
388 for(int i = 0; args[i]; i++)
389 {
390 command += args[i] + " "s;
391 }
392
393 log<level::ERR>("Couldn't exceute the command",
394 entry("ERRNO=%d", error),
395 entry("CMD=%s", command.c_str()));
396 elog<InternalFailure>();
397 }
398 else if (pid < 0)
399 {
400 auto error = errno;
401 log<level::ERR>("Error occurred during fork",
402 entry("ERRNO=%d", error));
403 elog<InternalFailure>();
404 }
405 else if (pid > 0)
406 {
407 while (waitpid(pid, &status, 0) == -1)
408 {
409 if (errno != EINTR)
410 { //Error other than EINTR
411 status = -1;
412 break;
413 }
414 }
415
416 if(status < 0)
417 {
418 std::string command = path + " "s;
419 for(int i = 0; args[i]; i++)
420 {
421 command += args[i] + " "s;
422 }
423
424 log<level::ERR>("Unable to execute the command",
425 entry("CMD=%s", command.c_str(),
426 entry("STATUS=%d", status)));
427 elog<InternalFailure>();
428 }
429 }
430
431}
432} //namespace internal
433
434namespace mac_address
435{
436
437constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
438constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
439constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
440constexpr auto propIntf = "org.freedesktop.DBus.Properties";
441constexpr auto methodGet = "Get";
442
443using DbusObjectPath = std::string;
444using DbusService = std::string;
445using DbusInterface = std::string;
446using ObjectTree = std::map<DbusObjectPath,
447 std::map<DbusService, std::vector<DbusInterface>>>;
448
449constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
450constexpr auto invNetworkIntf =
451 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
452constexpr auto invRoot = "/xyz/openbmc_project/inventory";
453
454std::string getfromInventory(sdbusplus::bus::bus& bus)
455{
456 std::vector<DbusInterface> interfaces;
457 interfaces.emplace_back(invNetworkIntf);
458
459 auto depth = 0;
460
461 auto mapperCall = bus.new_method_call(mapperBus,
462 mapperObj,
463 mapperIntf,
464 "GetSubTree");
465
466 mapperCall.append(invRoot, depth, interfaces);
467
468 auto mapperReply = bus.call(mapperCall);
469 if (mapperReply.is_method_error())
470 {
471 log<level::ERR>("Error in mapper call");
472 elog<InternalFailure>();
473 }
474
475 ObjectTree objectTree;
476 mapperReply.read(objectTree);
477
478 if (objectTree.empty())
479 {
480 log<level::ERR>("No Object has implemented the interface",
481 entry("INTERFACE=%s", invNetworkIntf));
482 elog<InternalFailure>();
483 }
484
485 // It is expected that only one object have impelmented this interface.
486
487 auto objPath = objectTree.begin()->first;
488 auto service = objectTree.begin()->second.begin()->first;
489
490 sdbusplus::message::variant<std::string> value;
491
492 auto method = bus.new_method_call(
493 service.c_str(),
494 objPath.c_str(),
495 propIntf,
496 methodGet);
497
498 method.append(invNetworkIntf, "MACAddress");
499
500 auto reply = bus.call(method);
501 if (reply.is_method_error())
502 {
503 log<level::ERR>("Failed to get MACAddress",
504 entry("PATH=%s", objPath.c_str()),
505 entry("INTERFACE=%s", invNetworkIntf));
506 elog<InternalFailure>();
507 }
508
509 reply.read(value);
510 return value.get<std::string>();
511}
512
513}//namespace mac_address
Ratan Gupta8804feb2017-05-25 10:49:57 +0530514}//namespace network
515}//namespace phosphor