blob: ff5e3f4861577ef67853f0a3a0a96e903a9b02d2 [file] [log] [blame]
Ratan Gupta233524c2017-05-27 11:47:31 +05301#include "routing_table.hpp"
Patrick Venture189d44e2018-07-09 12:30:59 -07002
Ratan Gupta233524c2017-05-27 11:47:31 +05303#include "util.hpp"
Ratan Gupta233524c2017-05-27 11:47:31 +05304
Ratan Gupta233524c2017-05-27 11:47:31 +05305#include <arpa/inet.h>
Patrick Venture189d44e2018-07-09 12:30:59 -07006#include <linux/rtnetlink.h>
7#include <net/if.h>
8#include <netinet/in.h>
Patrick Venture189d44e2018-07-09 12:30:59 -07009#include <sys/ioctl.h>
10#include <sys/socket.h>
11#include <sys/types.h>
12#include <unistd.h>
Ratan Gupta233524c2017-05-27 11:47:31 +053013
Patrick Venture189d44e2018-07-09 12:30:59 -070014#include <phosphor-logging/elog-errors.hpp>
15#include <phosphor-logging/log.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053016#include <stdexcept>
Patrick Venture189d44e2018-07-09 12:30:59 -070017#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053018
19namespace phosphor
20{
21namespace network
22{
23namespace route
24{
25
26using namespace phosphor::logging;
27using namespace sdbusplus::xyz::openbmc_project::Common::Error;
28
29Table::Table()
30{
31 try
32 {
33 getRoutes();
34 }
35 catch (InternalFailure& e)
36 {
37 commit<InternalFailure>();
38 }
Ratan Gupta233524c2017-05-27 11:47:31 +053039}
40
Gunnar Mills57d9c502018-09-14 14:42:34 -050041int Table::readNetLinkSock(int sockFd, std::array<char, BUFSIZE>& buf)
Ratan Gupta233524c2017-05-27 11:47:31 +053042{
43 struct nlmsghdr* nlHdr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 int readLen{};
45 int msgLen{};
Ratan Gupta233524c2017-05-27 11:47:31 +053046 uint8_t seqNum = 1;
47 uint8_t pID = getpid();
48 char* bufPtr = buf.data();
49
50 do
51 {
Gunnar Millsd75f0492017-10-25 20:33:32 -050052 // Receive response from the kernel
Ratan Gupta233524c2017-05-27 11:47:31 +053053 if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0)
54 {
55 auto error = errno;
56 log<level::ERR>("Socket recv failed:",
Gunnar Mills57d9c502018-09-14 14:42:34 -050057 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053058 elog<InternalFailure>();
Ratan Gupta233524c2017-05-27 11:47:31 +053059 }
60
61 nlHdr = reinterpret_cast<nlmsghdr*>(bufPtr);
62
63 // Check if the header is valid
64
Gunnar Mills57d9c502018-09-14 14:42:34 -050065 if ((NLMSG_OK(nlHdr, readLen) == 0) ||
66 (nlHdr->nlmsg_type == NLMSG_ERROR))
Ratan Gupta233524c2017-05-27 11:47:31 +053067 {
68
69 auto error = errno;
70 log<level::ERR>("Error validating header",
Gunnar Mills57d9c502018-09-14 14:42:34 -050071 entry("NLMSGTYPE=%d", nlHdr->nlmsg_type),
72 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053073 elog<InternalFailure>();
74 }
75
76 // Check if the its the last message
77 if (nlHdr->nlmsg_type == NLMSG_DONE)
78 {
79 break;
80 }
81 else
82 {
83 // Else move the pointer to buffer appropriately
84 bufPtr += readLen;
85 msgLen += readLen;
86 }
87
88 // Check if its a multi part message
89 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)
90 {
91 break;
92 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050093 } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pID));
Ratan Gupta233524c2017-05-27 11:47:31 +053094 return msgLen;
95}
96
97void Table::parseRoutes(const nlmsghdr* nlHdr)
98{
99 rtmsg* rtMsg = nullptr;
100 rtattr* rtAttr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500101 int rtLen{};
102 in_addr dstAddr{};
103 in_addr gateWayAddr{};
Ratan Gupta233524c2017-05-27 11:47:31 +0530104 char ifName[IF_NAMESIZE] = {};
105
106 rtMsg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nlHdr));
107
108 // If the route is not for AF_INET or does not belong to main routing table
109 // then return.
110 if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
111 {
112 return;
113 }
114
115 // get the rtattr field
116 rtAttr = reinterpret_cast<rtattr*>(RTM_RTA(rtMsg));
117
118 rtLen = RTM_PAYLOAD(nlHdr);
119
120 for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen))
121 {
122 switch (rtAttr->rta_type)
123 {
124 case RTA_OIF:
Gunnar Mills57d9c502018-09-14 14:42:34 -0500125 if_indextoname(*reinterpret_cast<int*>(RTA_DATA(rtAttr)),
126 ifName);
Ratan Gupta233524c2017-05-27 11:47:31 +0530127 break;
128 case RTA_GATEWAY:
Gunnar Mills57d9c502018-09-14 14:42:34 -0500129 gateWayAddr.s_addr =
130 *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
Ratan Gupta233524c2017-05-27 11:47:31 +0530131 break;
132 case RTA_DST:
133 dstAddr.s_addr = *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
134 break;
135 }
136 }
137
138 std::string dstStr;
139 std::string gatewayStr;
140
Ratan Guptab6242b02017-11-14 21:04:53 +0530141 if (dstAddr.s_addr == 0 && gateWayAddr.s_addr != 0)
Ratan Gupta233524c2017-05-27 11:47:31 +0530142 {
143 defaultGateway = reinterpret_cast<char*>(inet_ntoa(gateWayAddr));
144 }
145
146 dstStr = inet_ntoa(dstAddr);
147 gatewayStr = inet_ntoa(gateWayAddr);
148
149 Entry route(dstStr, gatewayStr, ifName);
Ratan Gupta4a5f08a2018-05-04 17:23:16 +0530150 // if there is already existing route for this network
151 // then ignore the next one as it would not be used by the
152 // routing policy
153 // So don't update the route entry for the network for which
154 // there is already a route exist.
155 if (routeList.find(dstStr) == routeList.end())
156 {
157 routeList.emplace(std::make_pair(dstStr, std::move(route)));
158 }
Ratan Gupta233524c2017-05-27 11:47:31 +0530159}
160
161Map Table::getRoutes()
162{
163 nlmsghdr* nlMsg = nullptr;
164 std::array<char, BUFSIZE> msgBuf = {0};
165
166 int sock = -1;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500167 int len{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530168
Gunnar Mills57d9c502018-09-14 14:42:34 -0500169 uint8_t msgSeq{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530170
171 // Create Socket
172 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
173 {
174 auto error = errno;
Gunnar Millsd75f0492017-10-25 20:33:32 -0500175 log<level::ERR>("Error occurred during socket creation",
Ratan Gupta233524c2017-05-27 11:47:31 +0530176 entry("ERRNO=%s", strerror(error)));
177 elog<InternalFailure>();
178 }
179
180 phosphor::Descriptor smartSock(sock);
181 sock = -1;
182
183 // point the header and the msg structure pointers into the buffer.
184 nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
185 // Length of message
186 nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
187 // Get the routes from kernel routing table
Gunnar Mills57d9c502018-09-14 14:42:34 -0500188 nlMsg->nlmsg_type = RTM_GETROUTE;
Ratan Gupta233524c2017-05-27 11:47:31 +0530189 // The message is a request for dump
190 nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
191
192 nlMsg->nlmsg_seq = msgSeq;
193 nlMsg->nlmsg_pid = getpid();
194
195 // Send the request
196 if (send(smartSock(), nlMsg, nlMsg->nlmsg_len, 0) < 0)
197 {
198 auto error = errno;
199 log<level::ERR>("Error occurred during send on netlink socket",
200 entry("ERRNO=%s", strerror(error)));
201 elog<InternalFailure>();
202 }
203
204 // Read the response
205 len = readNetLinkSock(smartSock(), msgBuf);
206
207 // Parse and print the response
208 for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len))
209 {
210 parseRoutes(nlMsg);
211 }
212 return routeList;
213}
214
Gunnar Mills57d9c502018-09-14 14:42:34 -0500215std::string Table::getGateway(int addressFamily, const std::string& ipaddress,
Ratan Gupta233524c2017-05-27 11:47:31 +0530216 uint8_t prefix) const
217{
218 std::string gateway;
219 std::string network = getNetworkID(addressFamily, ipaddress, prefix);
220 auto it = routeList.find(network);
221 if (it != routeList.end())
222 {
223 gateway = it->second.gateway;
224 }
225
226 return gateway;
227}
228
Gunnar Mills57d9c502018-09-14 14:42:34 -0500229} // namespace route
230} // namespace network
231} // namespace phosphor