blob: 41e4a6d9d1e9db3f522b9393c4259aebfa6e79b1 [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 }
42
43}
44
45int Table::readNetLinkSock(int sockFd, std::array<char,BUFSIZE>& buf)
46{
47 struct nlmsghdr* nlHdr = nullptr;
48 int readLen {};
49 int msgLen {};
50 uint8_t seqNum = 1;
51 uint8_t pID = getpid();
52 char* bufPtr = buf.data();
53
54 do
55 {
Gunnar Millsd75f0492017-10-25 20:33:32 -050056 // Receive response from the kernel
Ratan Gupta233524c2017-05-27 11:47:31 +053057 if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0)
58 {
59 auto error = errno;
60 log<level::ERR>("Socket recv failed:",
61 entry("ERROR=%s", strerror(error)));
62 elog<InternalFailure>();
63
64 }
65
66 nlHdr = reinterpret_cast<nlmsghdr*>(bufPtr);
67
68 // Check if the header is valid
69
70 if ((NLMSG_OK(nlHdr, readLen) == 0)
71 || (nlHdr->nlmsg_type == NLMSG_ERROR))
72 {
73
74 auto error = errno;
75 log<level::ERR>("Error validating header",
76 entry("NLMSGTYPE=%d", nlHdr->nlmsg_type),
77 entry("ERROR=%s", strerror(error)));
78 elog<InternalFailure>();
79 }
80
81 // Check if the its the last message
82 if (nlHdr->nlmsg_type == NLMSG_DONE)
83 {
84 break;
85 }
86 else
87 {
88 // Else move the pointer to buffer appropriately
89 bufPtr += readLen;
90 msgLen += readLen;
91 }
92
93 // Check if its a multi part message
94 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)
95 {
96 break;
97 }
98 }
99 while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pID));
100 return msgLen;
101}
102
103void Table::parseRoutes(const nlmsghdr* nlHdr)
104{
105 rtmsg* rtMsg = nullptr;
106 rtattr* rtAttr = nullptr;
107 int rtLen {};
108 in_addr dstAddr {};
109 in_addr gateWayAddr {};
110 char ifName[IF_NAMESIZE] = {};
111
112 rtMsg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nlHdr));
113
114 // If the route is not for AF_INET or does not belong to main routing table
115 // then return.
116 if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
117 {
118 return;
119 }
120
121 // get the rtattr field
122 rtAttr = reinterpret_cast<rtattr*>(RTM_RTA(rtMsg));
123
124 rtLen = RTM_PAYLOAD(nlHdr);
125
126 for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen))
127 {
128 switch (rtAttr->rta_type)
129 {
130 case RTA_OIF:
131 if_indextoname(*reinterpret_cast<int*>(RTA_DATA(rtAttr)), ifName);
132 break;
133 case RTA_GATEWAY:
134 gateWayAddr.s_addr = *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
135 break;
136 case RTA_DST:
137 dstAddr.s_addr = *reinterpret_cast<u_int*>(RTA_DATA(rtAttr));
138 break;
139 }
140 }
141
142 std::string dstStr;
143 std::string gatewayStr;
144
Ratan Guptab6242b02017-11-14 21:04:53 +0530145 if (dstAddr.s_addr == 0 && gateWayAddr.s_addr != 0)
Ratan Gupta233524c2017-05-27 11:47:31 +0530146 {
147 defaultGateway = reinterpret_cast<char*>(inet_ntoa(gateWayAddr));
148 }
149
150 dstStr = inet_ntoa(dstAddr);
151 gatewayStr = inet_ntoa(gateWayAddr);
152
153 Entry route(dstStr, gatewayStr, ifName);
Ratan Gupta4a5f08a2018-05-04 17:23:16 +0530154 // if there is already existing route for this network
155 // then ignore the next one as it would not be used by the
156 // routing policy
157 // So don't update the route entry for the network for which
158 // there is already a route exist.
159 if (routeList.find(dstStr) == routeList.end())
160 {
161 routeList.emplace(std::make_pair(dstStr, std::move(route)));
162 }
Ratan Gupta233524c2017-05-27 11:47:31 +0530163}
164
165Map Table::getRoutes()
166{
167 nlmsghdr* nlMsg = nullptr;
168 std::array<char, BUFSIZE> msgBuf = {0};
169
170 int sock = -1;
171 int len {0};
172
173 uint8_t msgSeq {0};
174
175 // Create Socket
176 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
177 {
178 auto error = errno;
Gunnar Millsd75f0492017-10-25 20:33:32 -0500179 log<level::ERR>("Error occurred during socket creation",
Ratan Gupta233524c2017-05-27 11:47:31 +0530180 entry("ERRNO=%s", strerror(error)));
181 elog<InternalFailure>();
182 }
183
184 phosphor::Descriptor smartSock(sock);
185 sock = -1;
186
187 // point the header and the msg structure pointers into the buffer.
188 nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
189 // Length of message
190 nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
191 // Get the routes from kernel routing table
192 nlMsg->nlmsg_type = RTM_GETROUTE;
193 // The message is a request for dump
194 nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
195
196 nlMsg->nlmsg_seq = msgSeq;
197 nlMsg->nlmsg_pid = getpid();
198
199 // Send the request
200 if (send(smartSock(), nlMsg, nlMsg->nlmsg_len, 0) < 0)
201 {
202 auto error = errno;
203 log<level::ERR>("Error occurred during send on netlink socket",
204 entry("ERRNO=%s", strerror(error)));
205 elog<InternalFailure>();
206 }
207
208 // Read the response
209 len = readNetLinkSock(smartSock(), msgBuf);
210
211 // Parse and print the response
212 for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len))
213 {
214 parseRoutes(nlMsg);
215 }
216 return routeList;
217}
218
219std::string Table::getGateway(int addressFamily,
220 const std::string& ipaddress,
221 uint8_t prefix) const
222{
223 std::string gateway;
224 std::string network = getNetworkID(addressFamily, ipaddress, prefix);
225 auto it = routeList.find(network);
226 if (it != routeList.end())
227 {
228 gateway = it->second.gateway;
229 }
230
231 return gateway;
232}
233
234}// namespace route
235}// namespace network
236}// namespace phosphor