blob: d96fe97a958a466e34f6962e3ac9ef4e12bb675d [file] [log] [blame]
Ratan Gupta3681a502017-06-17 19:20:04 +05301#include "util.hpp"
Ratan Gupta068a8cf2017-07-11 19:18:29 +05302
Ratan Gupta11cef802017-05-29 08:41:48 +05303#include "xyz/openbmc_project/Common/error.hpp"
4
5#include <phosphor-logging/log.hpp>
6#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +05307
Ratan Gupta3681a502017-06-17 19:20:04 +05308#include <arpa/inet.h>
9#include <dirent.h>
10#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +053011#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053012
Ratan Gupta8804feb2017-05-25 10:49:57 +053013#include <iostream>
14#include <list>
15#include <string>
16#include <algorithm>
Ratan Gupta8804feb2017-05-25 10:49:57 +053017
18namespace phosphor
19{
20namespace network
21{
Ratan Guptabc886292017-07-25 18:29:57 +053022
Ratan Gupta8804feb2017-05-25 10:49:57 +053023namespace
24{
25
26using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053027using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta8804feb2017-05-25 10:49:57 +053028
29uint8_t toV6Cidr(const std::string& subnetMask)
30{
31 uint8_t pos = 0;
32 uint8_t prevPos = 0;
33 uint8_t cidr = 0;
34 uint16_t buff {};
35 do
36 {
37 //subnet mask look like ffff:ffff::
38 // or ffff:c000::
39 pos = subnetMask.find(":", prevPos);
40 if (pos == std::string::npos)
41 {
42 break;
43 }
44
45 auto str = subnetMask.substr(prevPos, (pos - prevPos));
46 prevPos = pos + 1;
47
48 // String length is 0
49 if (!str.length())
50 {
51 return cidr;
52 }
53 //converts it into number.
54 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
55 {
56 log<level::ERR>("Invalid Mask",
Ratan Guptabc886292017-07-25 18:29:57 +053057 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +053058
59 return 0;
60 }
61
62 // convert the number into bitset
63 // and check for how many ones are there.
64 // if we don't have all the ones then make
65 // sure that all the ones should be left justify.
66
67 if (__builtin_popcount(buff) != 16)
68 {
69 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) != __builtin_popcount(buff))
70 {
71 log<level::ERR>("Invalid Mask",
72 entry("SUBNETMASK=%s", subnetMask));
73
74 return 0;
75 }
76 cidr += __builtin_popcount(buff);
77 return cidr;
78 }
79
80 cidr += 16;
81 }
82 while (1);
83
84 return cidr;
85}
86}// anonymous namespace
87
88uint8_t toCidr(int addressFamily, const std::string& subnetMask)
89{
90 if (addressFamily == AF_INET6)
91 {
92 return toV6Cidr(subnetMask);
93 }
94
95 uint32_t buff;
96
97 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
98 if (rc <= 0)
99 {
100 log<level::ERR>("inet_pton failed:",
Ratan Gupta11cef802017-05-29 08:41:48 +0530101 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530102 return 0;
103 }
104
105 buff = be32toh(buff);
106 // total no of bits - total no of leading zero == total no of ones
107 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) == __builtin_popcount(buff))
108 {
109 return __builtin_popcount(buff);
110 }
111 else
112 {
113 log<level::ERR>("Invalid Mask",
Ratan Gupta11cef802017-05-29 08:41:48 +0530114 entry("SUBNETMASK=%s", subnetMask));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530115 return 0;
116 }
117}
118
119std::string toMask(int addressFamily, uint8_t prefix)
120{
121 if (addressFamily == AF_INET6)
122 {
123 //TODO:- conversion for v6
124 return "";
125 }
126
127 if (prefix < 1 || prefix > 30)
128 {
129 log<level::ERR>("Invalid Prefix",
130 entry("PREFIX=%d", prefix));
131 return "";
132 }
133 /* Create the netmask from the number of bits */
134 unsigned long mask = 0;
135 for (auto i = 0 ; i < prefix ; i++)
136 {
137 mask |= 1 << (31 - i);
138 }
139 struct in_addr netmask;
140 netmask.s_addr = htonl(mask);
141 return inet_ntoa(netmask);
142}
143
Ratan Gupta11cef802017-05-29 08:41:48 +0530144std::string getNetworkID(int addressFamily, const std::string& ipaddress,
Ratan Guptabc886292017-07-25 18:29:57 +0530145 uint8_t prefix)
Ratan Gupta11cef802017-05-29 08:41:48 +0530146{
147 unsigned char* pntMask = nullptr;
148 unsigned char* pntNetwork = nullptr;
149 int bit {};
150 int offset {};
151 struct in6_addr netmask {};
152 const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
153 0xf8, 0xfc, 0xfe, 0xff
154 };
155
156 pntMask = reinterpret_cast<unsigned char*>(&netmask);
157
158 offset = prefix / 8;
159 bit = prefix % 8;
160
161 while (offset--)
162 {
163 *pntMask++ = 0xff;
164 }
165
166 if (bit)
167 {
168 *pntMask = maskbit[bit];
169 }
170
171 // convert ipaddres string into network address
172 struct in6_addr ipaddressNetwork;
173 if (inet_pton(addressFamily, ipaddress.c_str(), &ipaddressNetwork) <= 0)
174 {
175 log<level::ERR>("inet_pton failure",
Ratan Guptabc886292017-07-25 18:29:57 +0530176 entry("IPADDRESS=%s", ipaddress.c_str()));
Ratan Gupta11cef802017-05-29 08:41:48 +0530177 report<InternalFailure>();
178
179 return "";
180 }
181
182 // Now bit wise and gets you the network address
183 pntMask = reinterpret_cast<unsigned char*>(&netmask);
184 pntNetwork = reinterpret_cast<unsigned char*>(&ipaddressNetwork);
185
186 for (int i = 0; i < 16 ; i++)
187 {
188 pntNetwork[i] = pntNetwork[i] & pntMask[i];
189 }
190
191 //convert the network address into string fomat.
192 char networkString[INET6_ADDRSTRLEN] = { 0 };
193 if (inet_ntop(addressFamily, &ipaddressNetwork, networkString,
194 INET6_ADDRSTRLEN) == NULL)
195 {
196 log<level::ERR>("inet_ntop failure");
197 report<InternalFailure>();
198 }
199 return networkString;
200}
201
Ratan Gupta8804feb2017-05-25 10:49:57 +0530202bool isLinkLocal(const std::string& address)
203{
204 std::string linklocal = "fe80";
205 return std::mismatch(linklocal.begin(), linklocal.end(),
206 address.begin()).first == linklocal.end() ?
Ratan Guptabc886292017-07-25 18:29:57 +0530207 true : false;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530208}
209
Ratan Gupta3681a502017-06-17 19:20:04 +0530210IntfAddrMap getInterfaceAddrs()
211{
Ratan Guptabc886292017-07-25 18:29:57 +0530212 IntfAddrMap intfMap {};
213 AddrList addrList {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530214 struct ifaddrs* ifaddr = nullptr;
215
216 // attempt to fill struct with ifaddrs
217 if (getifaddrs(&ifaddr) == -1)
218 {
219 auto error = errno;
220 log<level::ERR>("Error occurred during the getifaddrs call",
221 entry("ERRNO=%s", strerror(error)));
222 elog<InternalFailure>();
223 }
224
225 AddrPtr ifaddrPtr(ifaddr);
226 ifaddr = nullptr;
227
Ratan Guptabc886292017-07-25 18:29:57 +0530228 std::string intfName {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530229
230 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
231 {
232 // walk interfaces
233 if (ifa->ifa_addr == nullptr)
234 {
235 continue;
236 }
237
238 // get only INET interfaces not ipv6
239 if (ifa->ifa_addr->sa_family == AF_INET ||
240 ifa->ifa_addr->sa_family == AF_INET6)
241 {
242 // if loopback, or not running ignore
243 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
244 !(ifa->ifa_flags & IFF_RUNNING))
245 {
246 continue;
247 }
248 // if the interface name is not same as the previous
249 // iteration then add the addr list into
250 // the map.
251 if (intfName != "" && intfName != std::string(ifa->ifa_name))
252 {
253 intfMap.emplace(intfName, addrList);
254 addrList.clear();
255 }
256 intfName = ifa->ifa_name;
Ratan Guptabc886292017-07-25 18:29:57 +0530257 AddrInfo info {};
Ratan Gupta3681a502017-06-17 19:20:04 +0530258 char ip[INET6_ADDRSTRLEN] = { 0 };
259 char subnetMask[INET6_ADDRSTRLEN] = { 0 };
260
261 if (ifa->ifa_addr->sa_family == AF_INET)
262 {
263
264 inet_ntop(ifa->ifa_addr->sa_family,
265 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
266 ip,
267 sizeof(ip));
268
269 inet_ntop(ifa->ifa_addr->sa_family,
270 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
271 subnetMask,
272 sizeof(subnetMask));
273
274 }
275 else
276 {
277 inet_ntop(ifa->ifa_addr->sa_family,
278 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
279 ip,
280 sizeof(ip));
281
282 inet_ntop(ifa->ifa_addr->sa_family,
283 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
284 subnetMask,
285 sizeof(subnetMask));
286
287 }
288
289 info.addrType = ifa->ifa_addr->sa_family;
290 info.ipaddress = ip;
291 info.prefix = toCidr(info.addrType, std::string(subnetMask));
292 addrList.emplace_back(info);
293 }
294 }
295 intfMap.emplace(intfName, addrList);
296 return intfMap;
297}
298
Ratan Guptabc886292017-07-25 18:29:57 +0530299void deleteInterface(const std::string& intf)
300{
301 pid_t pid = fork();
302 int status {};
303
304 if (pid == 0)
305 {
306
307 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
308 auto error = errno;
309 log<level::ERR>("Couldn't delete the device",
310 entry("ERRNO=%d", error),
311 entry("INTF=%s", intf.c_str()));
312 elog<InternalFailure>();
313 }
314 else if (pid < 0)
315 {
316 auto error = errno;
317 log<level::ERR>("Error occurred during fork",
318 entry("ERRNO=%d", error));
319 elog<InternalFailure>();
320 }
321 else if (pid > 0)
322 {
323 while (waitpid(pid, &status, 0) == -1)
324 {
325 if (errno != EINTR)
326 { /* Error other than EINTR */
327 status = -1;
328 break;
329 }
330 }
331
332 if(status < 0)
333 {
334 log<level::ERR>("Unable to delete the interface",
335 entry("INTF=%s", intf.c_str(),
336 entry("STATUS=%d", status)));
337 elog<InternalFailure>();
338 }
339 }
340}
341
Ratan Gupta8804feb2017-05-25 10:49:57 +0530342}//namespace network
343}//namespace phosphor