blob: 6a17037d7487c85e6b5d891141349ba348fc40f4 [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>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/ioctl.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15#include <unistd.h>
Ratan Gupta233524c2017-05-27 11:47:31 +053016
Patrick Venture189d44e2018-07-09 12:30:59 -070017#include <phosphor-logging/elog-errors.hpp>
18#include <phosphor-logging/log.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053019#include <stdexcept>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053021
22namespace phosphor
23{
24namespace network
25{
26namespace route
27{
28
29using namespace phosphor::logging;
30using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31
32Table::Table()
33{
34 try
35 {
36 getRoutes();
37 }
38 catch (InternalFailure& e)
39 {
40 commit<InternalFailure>();
41 }
Ratan Gupta233524c2017-05-27 11:47:31 +053042}
43
Gunnar Mills57d9c502018-09-14 14:42:34 -050044int Table::readNetLinkSock(int sockFd, std::array<char, BUFSIZE>& buf)
Ratan Gupta233524c2017-05-27 11:47:31 +053045{
46 struct nlmsghdr* nlHdr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -050047 int readLen{};
48 int msgLen{};
Ratan Gupta233524c2017-05-27 11:47:31 +053049 uint8_t seqNum = 1;
50 uint8_t pID = getpid();
51 char* bufPtr = buf.data();
52
53 do
54 {
Gunnar Millsd75f0492017-10-25 20:33:32 -050055 // Receive response from the kernel
Ratan Gupta233524c2017-05-27 11:47:31 +053056 if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0)
57 {
58 auto error = errno;
59 log<level::ERR>("Socket recv failed:",
Gunnar Mills57d9c502018-09-14 14:42:34 -050060 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053061 elog<InternalFailure>();
Ratan Gupta233524c2017-05-27 11:47:31 +053062 }
63
64 nlHdr = reinterpret_cast<nlmsghdr*>(bufPtr);
65
66 // Check if the header is valid
67
Gunnar Mills57d9c502018-09-14 14:42:34 -050068 if ((NLMSG_OK(nlHdr, readLen) == 0) ||
69 (nlHdr->nlmsg_type == NLMSG_ERROR))
Ratan Gupta233524c2017-05-27 11:47:31 +053070 {
71
72 auto error = errno;
73 log<level::ERR>("Error validating header",
Gunnar Mills57d9c502018-09-14 14:42:34 -050074 entry("NLMSGTYPE=%d", nlHdr->nlmsg_type),
75 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053076 elog<InternalFailure>();
77 }
78
79 // Check if the its the last message
80 if (nlHdr->nlmsg_type == NLMSG_DONE)
81 {
82 break;
83 }
84 else
85 {
86 // Else move the pointer to buffer appropriately
87 bufPtr += readLen;
88 msgLen += readLen;
89 }
90
91 // Check if its a multi part message
92 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)
93 {
94 break;
95 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050096 } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pID));
Ratan Gupta233524c2017-05-27 11:47:31 +053097 return msgLen;
98}
99
100void Table::parseRoutes(const nlmsghdr* nlHdr)
101{
102 rtmsg* rtMsg = nullptr;
103 rtattr* rtAttr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500104 int rtLen{};
105 in_addr dstAddr{};
106 in_addr gateWayAddr{};
Ratan Gupta233524c2017-05-27 11:47:31 +0530107 char ifName[IF_NAMESIZE] = {};
108
109 rtMsg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nlHdr));
110
111 // If the route is not for AF_INET or does not belong to main routing table
112 // then return.
113 if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
114 {
115 return;
116 }
117
118 // get the rtattr field
119 rtAttr = reinterpret_cast<rtattr*>(RTM_RTA(rtMsg));
120
121 rtLen = RTM_PAYLOAD(nlHdr);
122
123 for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen))
124 {
125 switch (rtAttr->rta_type)
126 {
127 case RTA_OIF:
Gunnar Mills57d9c502018-09-14 14:42:34 -0500128 if_indextoname(*reinterpret_cast<int*>(RTA_DATA(rtAttr)),
129 ifName);
Ratan Gupta233524c2017-05-27 11:47:31 +0530130 break;
131 case RTA_GATEWAY:
Gunnar Mills57d9c502018-09-14 14:42:34 -0500132 gateWayAddr.s_addr =
133 *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
Ratan Gupta233524c2017-05-27 11:47:31 +0530134 break;
135 case RTA_DST:
136 dstAddr.s_addr = *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
137 break;
138 }
139 }
140
141 std::string dstStr;
142 std::string gatewayStr;
143
Ratan Guptab6242b02017-11-14 21:04:53 +0530144 if (dstAddr.s_addr == 0 && gateWayAddr.s_addr != 0)
Ratan Gupta233524c2017-05-27 11:47:31 +0530145 {
146 defaultGateway = reinterpret_cast<char*>(inet_ntoa(gateWayAddr));
147 }
148
149 dstStr = inet_ntoa(dstAddr);
150 gatewayStr = inet_ntoa(gateWayAddr);
151
152 Entry route(dstStr, gatewayStr, ifName);
Ratan Gupta4a5f08a2018-05-04 17:23:16 +0530153 // if there is already existing route for this network
154 // then ignore the next one as it would not be used by the
155 // routing policy
156 // So don't update the route entry for the network for which
157 // there is already a route exist.
158 if (routeList.find(dstStr) == routeList.end())
159 {
160 routeList.emplace(std::make_pair(dstStr, std::move(route)));
161 }
Ratan Gupta233524c2017-05-27 11:47:31 +0530162}
163
164Map Table::getRoutes()
165{
166 nlmsghdr* nlMsg = nullptr;
167 std::array<char, BUFSIZE> msgBuf = {0};
168
169 int sock = -1;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500170 int len{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530171
Gunnar Mills57d9c502018-09-14 14:42:34 -0500172 uint8_t msgSeq{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530173
174 // Create Socket
175 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
176 {
177 auto error = errno;
Gunnar Millsd75f0492017-10-25 20:33:32 -0500178 log<level::ERR>("Error occurred during socket creation",
Ratan Gupta233524c2017-05-27 11:47:31 +0530179 entry("ERRNO=%s", strerror(error)));
180 elog<InternalFailure>();
181 }
182
183 phosphor::Descriptor smartSock(sock);
184 sock = -1;
185
186 // point the header and the msg structure pointers into the buffer.
187 nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
188 // Length of message
189 nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
190 // Get the routes from kernel routing table
Gunnar Mills57d9c502018-09-14 14:42:34 -0500191 nlMsg->nlmsg_type = RTM_GETROUTE;
Ratan Gupta233524c2017-05-27 11:47:31 +0530192 // The message is a request for dump
193 nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
194
195 nlMsg->nlmsg_seq = msgSeq;
196 nlMsg->nlmsg_pid = getpid();
197
198 // Send the request
199 if (send(smartSock(), nlMsg, nlMsg->nlmsg_len, 0) < 0)
200 {
201 auto error = errno;
202 log<level::ERR>("Error occurred during send on netlink socket",
203 entry("ERRNO=%s", strerror(error)));
204 elog<InternalFailure>();
205 }
206
207 // Read the response
208 len = readNetLinkSock(smartSock(), msgBuf);
209
210 // Parse and print the response
211 for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len))
212 {
213 parseRoutes(nlMsg);
214 }
215 return routeList;
216}
217
Gunnar Mills57d9c502018-09-14 14:42:34 -0500218std::string Table::getGateway(int addressFamily, const std::string& ipaddress,
Ratan Gupta233524c2017-05-27 11:47:31 +0530219 uint8_t prefix) const
220{
221 std::string gateway;
222 std::string network = getNetworkID(addressFamily, ipaddress, prefix);
223 auto it = routeList.find(network);
224 if (it != routeList.end())
225 {
226 gateway = it->second.gateway;
227 }
228
229 return gateway;
230}
231
Gunnar Mills57d9c502018-09-14 14:42:34 -0500232} // namespace route
233} // namespace network
234} // namespace phosphor