blob: c4e989a7c92c0a5cfb8c7a0d534babba4eae1b88 [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 {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530243 struct ifaddrs* ifaddr = nullptr;
244
245 // attempt to fill struct with ifaddrs
246 if (getifaddrs(&ifaddr) == -1)
247 {
248 auto error = errno;
249 log<level::ERR>("Error occurred during the getifaddrs call",
250 entry("ERRNO=%s", strerror(error)));
251 elog<InternalFailure>();
252 }
253
254 AddrPtr ifaddrPtr(ifaddr);
255 ifaddr = nullptr;
256
Ratan Guptabc886292017-07-25 18:29:57 +0530257 std::string intfName {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530258
259 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
260 {
261 // walk interfaces
262 if (ifa->ifa_addr == nullptr)
263 {
264 continue;
265 }
266
267 // get only INET interfaces not ipv6
268 if (ifa->ifa_addr->sa_family == AF_INET ||
269 ifa->ifa_addr->sa_family == AF_INET6)
270 {
271 // if loopback, or not running ignore
272 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
273 !(ifa->ifa_flags & IFF_RUNNING))
274 {
275 continue;
276 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530277 intfName = ifa->ifa_name;
Ratan Guptabc886292017-07-25 18:29:57 +0530278 AddrInfo info {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530279 char ip[INET6_ADDRSTRLEN] = { 0 };
280 char subnetMask[INET6_ADDRSTRLEN] = { 0 };
281
282 if (ifa->ifa_addr->sa_family == AF_INET)
283 {
284
285 inet_ntop(ifa->ifa_addr->sa_family,
286 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
287 ip,
288 sizeof(ip));
289
290 inet_ntop(ifa->ifa_addr->sa_family,
291 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
292 subnetMask,
293 sizeof(subnetMask));
294
295 }
296 else
297 {
298 inet_ntop(ifa->ifa_addr->sa_family,
299 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
300 ip,
301 sizeof(ip));
302
303 inet_ntop(ifa->ifa_addr->sa_family,
304 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
305 subnetMask,
306 sizeof(subnetMask));
307
308 }
309
310 info.addrType = ifa->ifa_addr->sa_family;
311 info.ipaddress = ip;
312 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700313 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530314 }
315 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530316 return intfMap;
317}
318
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530319InterfaceList getInterfaces()
320{
321 InterfaceList interfaces {};
322 struct ifaddrs* ifaddr = nullptr;
323
324 // attempt to fill struct with ifaddrs
325 if (getifaddrs(&ifaddr) == -1)
326 {
327 auto error = errno;
328 log<level::ERR>("Error occurred during the getifaddrs call",
329 entry("ERRNO=%d", error));
330 elog<InternalFailure>();
331 }
332
333 AddrPtr ifaddrPtr(ifaddr);
334 ifaddr = nullptr;
335
336 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
337 {
338 // walk interfaces
339 // if loopback, or not running ignore
340 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
341 !(ifa->ifa_flags & IFF_RUNNING))
342 {
343 continue;
344 }
345 interfaces.emplace(ifa->ifa_name);
346 }
347 return interfaces;
348}
349
350
Ratan Guptabc886292017-07-25 18:29:57 +0530351void deleteInterface(const std::string& intf)
352{
353 pid_t pid = fork();
354 int status {};
355
356 if (pid == 0)
357 {
358
359 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
360 auto error = errno;
361 log<level::ERR>("Couldn't delete the device",
362 entry("ERRNO=%d", error),
363 entry("INTF=%s", intf.c_str()));
364 elog<InternalFailure>();
365 }
366 else if (pid < 0)
367 {
368 auto error = errno;
369 log<level::ERR>("Error occurred during fork",
370 entry("ERRNO=%d", error));
371 elog<InternalFailure>();
372 }
373 else if (pid > 0)
374 {
375 while (waitpid(pid, &status, 0) == -1)
376 {
377 if (errno != EINTR)
378 { /* Error other than EINTR */
379 status = -1;
380 break;
381 }
382 }
383
384 if(status < 0)
385 {
386 log<level::ERR>("Unable to delete the interface",
387 entry("INTF=%s", intf.c_str(),
388 entry("STATUS=%d", status)));
389 elog<InternalFailure>();
390 }
391 }
392}
393
Ratan Gupta56187e72017-08-13 09:40:14 +0530394bool getDHCPValue(const std::string& confDir, const std::string& intf)
395{
396 bool dhcp = false;
397 // Get the interface mode value from systemd conf
398 //using namespace std::string_literals;
399 fs::path confPath = confDir;
400 std::string fileName = systemd::config::networkFilePrefix + intf +
401 systemd::config::networkFileSuffix;
402 confPath /= fileName;
403
Ratan Guptac27170a2017-11-22 15:44:42 +0530404 auto rc = config::ReturnCode::SUCCESS;
405 config::ValueList values;
406 config::Parser parser(confPath.string());
407
408 std::tie(rc, values) = parser.getValues("Network", "DHCP");
409 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530410 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530411 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
412 entry("RC=%d", rc));
413 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530414 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530415 // There will be only single value for DHCP key.
416 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530417 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530418 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530419 }
420 return dhcp;
421}
422
Ratan Guptabd303b12017-08-18 17:10:07 +0530423namespace internal
424{
Ratan Gupta56187e72017-08-13 09:40:14 +0530425
Ratan Guptabd303b12017-08-18 17:10:07 +0530426void executeCommandinChildProcess(const char* path, char** args)
427{
428 using namespace std::string_literals;
429 pid_t pid = fork();
430 int status {};
431
432 if (pid == 0)
433 {
434 execv(path, args);
435 auto error = errno;
436 // create the command from var args.
437 std::string command = path + " "s;
438
439 for(int i = 0; args[i]; i++)
440 {
441 command += args[i] + " "s;
442 }
443
444 log<level::ERR>("Couldn't exceute the command",
445 entry("ERRNO=%d", error),
446 entry("CMD=%s", command.c_str()));
447 elog<InternalFailure>();
448 }
449 else if (pid < 0)
450 {
451 auto error = errno;
452 log<level::ERR>("Error occurred during fork",
453 entry("ERRNO=%d", error));
454 elog<InternalFailure>();
455 }
456 else if (pid > 0)
457 {
458 while (waitpid(pid, &status, 0) == -1)
459 {
460 if (errno != EINTR)
461 { //Error other than EINTR
462 status = -1;
463 break;
464 }
465 }
466
467 if(status < 0)
468 {
469 std::string command = path + " "s;
470 for(int i = 0; args[i]; i++)
471 {
472 command += args[i] + " "s;
473 }
474
475 log<level::ERR>("Unable to execute the command",
476 entry("CMD=%s", command.c_str(),
477 entry("STATUS=%d", status)));
478 elog<InternalFailure>();
479 }
480 }
481
482}
483} //namespace internal
484
485namespace mac_address
486{
487
488constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
489constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
490constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
491constexpr auto propIntf = "org.freedesktop.DBus.Properties";
492constexpr auto methodGet = "Get";
493
494using DbusObjectPath = std::string;
495using DbusService = std::string;
496using DbusInterface = std::string;
497using ObjectTree = std::map<DbusObjectPath,
498 std::map<DbusService, std::vector<DbusInterface>>>;
499
500constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
501constexpr auto invNetworkIntf =
502 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
503constexpr auto invRoot = "/xyz/openbmc_project/inventory";
504
505std::string getfromInventory(sdbusplus::bus::bus& bus)
506{
507 std::vector<DbusInterface> interfaces;
508 interfaces.emplace_back(invNetworkIntf);
509
510 auto depth = 0;
511
512 auto mapperCall = bus.new_method_call(mapperBus,
513 mapperObj,
514 mapperIntf,
515 "GetSubTree");
516
517 mapperCall.append(invRoot, depth, interfaces);
518
519 auto mapperReply = bus.call(mapperCall);
520 if (mapperReply.is_method_error())
521 {
522 log<level::ERR>("Error in mapper call");
523 elog<InternalFailure>();
524 }
525
526 ObjectTree objectTree;
527 mapperReply.read(objectTree);
528
529 if (objectTree.empty())
530 {
531 log<level::ERR>("No Object has implemented the interface",
532 entry("INTERFACE=%s", invNetworkIntf));
533 elog<InternalFailure>();
534 }
535
Gunnar Millsa251a782017-09-26 16:49:08 -0500536 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530537
538 auto objPath = objectTree.begin()->first;
539 auto service = objectTree.begin()->second.begin()->first;
540
541 sdbusplus::message::variant<std::string> value;
542
543 auto method = bus.new_method_call(
544 service.c_str(),
545 objPath.c_str(),
546 propIntf,
547 methodGet);
548
549 method.append(invNetworkIntf, "MACAddress");
550
551 auto reply = bus.call(method);
552 if (reply.is_method_error())
553 {
554 log<level::ERR>("Failed to get MACAddress",
555 entry("PATH=%s", objPath.c_str()),
556 entry("INTERFACE=%s", invNetworkIntf));
557 elog<InternalFailure>();
558 }
559
560 reply.read(value);
561 return value.get<std::string>();
562}
563
564}//namespace mac_address
Ratan Gupta8804feb2017-05-25 10:49:57 +0530565}//namespace network
566}//namespace phosphor