blob: 1f36815d707a910d01bbc8c5ef239aac932e93a9 [file] [log] [blame]
Ratan Gupta82549cc2017-04-21 08:45:23 +05301#include "config.h"
2#include "ipaddress.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05303#include "ethernet_interface.hpp"
Ratan Gupta4f1c18b2017-05-25 12:59:35 +05304#include "network_manager.hpp"
Ratan Guptafc2c7242017-05-29 08:46:06 +05305#include "routing_table.hpp"
Ratan Gupta91a99cc2017-04-14 16:32:09 +05306
7#include <phosphor-logging/log.hpp>
8
Ratan Gupta82549cc2017-04-21 08:45:23 +05309#include <arpa/inet.h>
Ratan Gupta91a99cc2017-04-14 16:32:09 +053010#include <linux/ethtool.h>
11#include <net/if.h>
12#include <linux/sockios.h>
13#include <netinet/in.h>
14#include <sys/ioctl.h>
15#include <sys/socket.h>
16#include <unistd.h>
17
Ratan Gupta82549cc2017-04-21 08:45:23 +053018#include <string>
19#include <algorithm>
Ratan Gupta65e5abe2017-05-23 13:20:44 +053020#include <sstream>
Ratan Gupta82549cc2017-04-21 08:45:23 +053021#include <experimental/filesystem>
22
Ratan Gupta91a99cc2017-04-14 16:32:09 +053023namespace phosphor
24{
25namespace network
26{
27
28using namespace phosphor::logging;
29constexpr auto MAC_ADDRESS_FORMAT = "%02X:%02X:%02X:%02X:%02X:%02X";
30constexpr size_t SIZE_MAC = 18;
31constexpr size_t SIZE_BUFF = 512;
32
33EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
34 const std::string& objPath,
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053035 bool dhcpEnabled,
36 Manager& parent) :
Ratan Gupta82549cc2017-04-21 08:45:23 +053037 Ifaces(bus, objPath.c_str(), true),
Ratan Gupta4f1c18b2017-05-25 12:59:35 +053038 bus(bus),
Ratan Gupta47722dc2017-05-26 18:32:23 +053039 manager(parent),
40 objPath(objPath)
Ratan Gupta91a99cc2017-04-14 16:32:09 +053041{
42 auto intfName = objPath.substr(objPath.rfind("/") + 1);
43 interfaceName(intfName);
44 dHCPEnabled(dhcpEnabled);
45 mACAddress(getMACAddress());
Ratan Gupta29b0e432017-05-25 12:51:40 +053046 // Emit deferred signal.
47 this->emit_object_added();
48}
49
50void EthernetInterface::setAddressList(const AddrList& addrs)
51{
Ratan Gupta82549cc2017-04-21 08:45:23 +053052 std::string gateway;
53
54 IP::Protocol addressType = IP::Protocol::IPv4;
Ratan Gupta29b0e432017-05-25 12:51:40 +053055 IP::AddressOrigin origin = IP::AddressOrigin::Static;
Ratan Guptafc2c7242017-05-29 08:46:06 +053056 route::Table routingTable;
Ratan Gupta82549cc2017-04-21 08:45:23 +053057 for (auto addr : addrs)
58 {
59 if (addr.addrType == AF_INET6)
60 {
61 addressType = IP::Protocol::IPv6;
62 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053063 if (dHCPEnabled())
64 {
65 origin = IP::AddressOrigin::DHCP;
66 }
67 else if (isLinkLocal(addr.ipaddress))
68 {
69 origin = IP::AddressOrigin::LinkLocal;
70 }
71 gateway = routingTable.getGateway(addr.addrType, addr.ipaddress, addr.prefix);
Ratan Gupta82549cc2017-04-21 08:45:23 +053072
Ratan Gupta65e5abe2017-05-23 13:20:44 +053073 std::string ipAddressObjectPath = generateObjectPath(addressType,
74 addr.ipaddress,
75 addr.prefix,
76 gateway);
Ratan Guptafc2c7242017-05-29 08:46:06 +053077
Ratan Gupta82549cc2017-04-21 08:45:23 +053078 this->addrs.emplace(
79 std::make_pair(
Ratan Gupta719f83a2017-06-02 11:54:53 +053080 addr.ipaddress,
81 std::make_unique<phosphor::network::IPAddress>(
82 bus,
83 ipAddressObjectPath.c_str(),
84 *this,
85 addressType,
Ratan Gupta82549cc2017-04-21 08:45:23 +053086 addr.ipaddress,
Ratan Gupta29b0e432017-05-25 12:51:40 +053087 origin,
Ratan Gupta719f83a2017-06-02 11:54:53 +053088 addr.prefix,
89 gateway)));
Ratan Gupta82549cc2017-04-21 08:45:23 +053090 }
Ratan Guptafc2c7242017-05-29 08:46:06 +053091
Ratan Gupta91a99cc2017-04-14 16:32:09 +053092}
93
Ratan Gupta82549cc2017-04-21 08:45:23 +053094void EthernetInterface::iP(IP::Protocol protType,
95 std::string ipaddress,
96 uint8_t prefixLength,
97 std::string gateway)
98{
Ratan Guptafc2c7242017-05-29 08:46:06 +053099
100 if (dHCPEnabled())
101 {
Ratan Gupta82e1ef92017-06-15 08:39:15 +0530102 log<level::INFO>("DHCP enabled on the interface"),
103 entry("INTERFACE=%s",interfaceName());
Ratan Guptafc2c7242017-05-29 08:46:06 +0530104 return;
105 }
106
Ratan Gupta29b0e432017-05-25 12:51:40 +0530107 IP::AddressOrigin origin = IP::AddressOrigin::Static;
108
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530109 std::string objectPath = generateObjectPath(protType,
110 ipaddress,
111 prefixLength,
112 gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530113
114 this->addrs.emplace(
115 std::make_pair(ipaddress,
116 std::make_unique<phosphor::network::IPAddress>(
117 bus,
118 objectPath.c_str(),
119 *this,
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530120 protType,
Ratan Gupta82549cc2017-04-21 08:45:23 +0530121 ipaddress,
Ratan Gupta29b0e432017-05-25 12:51:40 +0530122 origin,
Ratan Gupta82549cc2017-04-21 08:45:23 +0530123 prefixLength,
124 gateway)));
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530125
126 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530127}
128
129
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530130/*
131Note: We don't have support for ethtool now
132will enable this code once we bring the ethtool
133in the image.
134TODO: https://github.com/openbmc/openbmc/issues/1484
135*/
Ratan Gupta82549cc2017-04-21 08:45:23 +0530136
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530137InterfaceInfo EthernetInterface::getInterfaceInfo() const
138{
139 int sock{-1};
140 struct ifreq ifr{0};
141 struct ethtool_cmd edata{0};
142 LinkSpeed speed {0};
143 Autoneg autoneg {0};
144 DuplexMode duplex {0};
145 do
146 {
147 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
148 if (sock < 0)
149 {
150 log<level::ERR>("socket creation failed:",
151 entry("ERROR=%s", strerror(errno)));
152 break;
153 }
154
155 strncpy(ifr.ifr_name, interfaceName().c_str(), sizeof(ifr.ifr_name));
156 ifr.ifr_data = reinterpret_cast<char*>(&edata);
157
158 edata.cmd = ETHTOOL_GSET;
159
160 if (ioctl(sock, SIOCETHTOOL, &ifr) < 0)
161 {
162 log<level::ERR>("ioctl failed for SIOCETHTOOL:",
163 entry("ERROR=%s", strerror(errno)));
164 break;
165
166 }
167 speed = edata.speed;
168 duplex = edata.duplex;
169 autoneg = edata.autoneg;
170 }
171 while (0);
172
173 if (sock)
174 {
175 close(sock);
176 }
177 return std::make_tuple(speed, duplex, autoneg);
178}
179
180/** @brief get the mac address of the interface.
181 * @return macaddress on success
182 */
183
184std::string EthernetInterface::getMACAddress() const
185{
186 struct ifreq ifr;
187 struct ifconf ifc;
188 char buf[SIZE_BUFF];
189 char macAddress[SIZE_MAC] = "";
190
191 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
192 if (sock < 0)
193 {
194 log<level::ERR>("socket creation failed:",
195 entry("ERROR=%s", strerror(errno)));
196 return macAddress;
197 }
198
199 ifc.ifc_len = sizeof(buf);
200 ifc.ifc_buf = buf;
201 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
202 {
203 log<level::ERR>("ioctl failed for SIOCGIFCONF:",
204 entry("ERROR=%s", strerror(errno)));
205 return macAddress;
206 }
207
208 struct ifreq* it = ifc.ifc_req;
209 const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
210
211 for (; it != end; ++it)
212 {
213 if (interfaceName() == it->ifr_name)
214 {
215 break;
216 }
217 }
218 if (interfaceName() == it->ifr_name)
219 {
220 strcpy(ifr.ifr_name, it->ifr_name);
221 if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
222 {
223 log<level::ERR>("ioctl failed for SIOCGIFHWADDR:",
224 entry("ERROR=%s", strerror(errno)));
225 return macAddress;
226 }
227
228 snprintf(macAddress, SIZE_MAC, MAC_ADDRESS_FORMAT,
229 ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
230 ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
231 ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
232 }
233 return macAddress;
234}
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530235
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530236std::string EthernetInterface::generateId(const std::string& ipaddress,
237 uint8_t prefixLength,
238 const std::string& gateway)
Ratan Gupta82549cc2017-04-21 08:45:23 +0530239{
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530240 std::stringstream hexId;
241 std::string hashString = ipaddress;
242 hashString += std::to_string(prefixLength);
243 hashString += gateway;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530244
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530245 // Only want 8 hex digits.
246 hexId << std::hex << ((std::hash<std::string> {}(
Ratan Guptafc2c7242017-05-29 08:46:06 +0530247 hashString)) & 0xFFFFFFFF);
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530248 return hexId.str();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530249}
250
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530251void EthernetInterface::deleteObject(const std::string& ipaddress)
252{
Ratan Gupta29b0e432017-05-25 12:51:40 +0530253 auto it = addrs.find(ipaddress);
Ratan Guptafc2c7242017-05-29 08:46:06 +0530254 if (it == addrs.end())
Ratan Gupta29b0e432017-05-25 12:51:40 +0530255 {
Ratan Guptafc2c7242017-05-29 08:46:06 +0530256 log<level::ERR>("DeleteObject:Unable to find the object.");
257 return;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530258 }
259 this->addrs.erase(it);
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530260 manager.writeToConfigurationFile();
Ratan Gupta82549cc2017-04-21 08:45:23 +0530261}
262
Ratan Gupta65e5abe2017-05-23 13:20:44 +0530263std::string EthernetInterface::generateObjectPath(IP::Protocol addressType,
264 const std::string& ipaddress,
265 uint8_t prefixLength,
266 const std::string& gateway) const
Ratan Gupta82549cc2017-04-21 08:45:23 +0530267{
Ratan Gupta82549cc2017-04-21 08:45:23 +0530268 std::string type = convertForMessage(addressType);
Ratan Gupta29b0e432017-05-25 12:51:40 +0530269 type = type.substr(type.rfind('.') + 1);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530270 std::transform(type.begin(), type.end(), type.begin(), ::tolower);
271
272 std::experimental::filesystem::path objectPath;
Ratan Gupta47722dc2017-05-26 18:32:23 +0530273 objectPath /= objPath;
Ratan Gupta82549cc2017-04-21 08:45:23 +0530274 objectPath /= type;
Ratan Gupta29b0e432017-05-25 12:51:40 +0530275 objectPath /= generateId(ipaddress, prefixLength, gateway);
Ratan Gupta82549cc2017-04-21 08:45:23 +0530276 return objectPath.string();
Ratan Gupta2eff84f2017-04-20 19:19:15 +0530277}
278
Ratan Gupta91a99cc2017-04-14 16:32:09 +0530279}//namespace network
280}//namespace phosphor