blob: ffbeecb53e460be06393c0fb77f369a4dc8e4bac [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
William A. Kennington IIId81a0982019-02-01 21:10:27 -080014#include <optional>
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <phosphor-logging/elog-errors.hpp>
16#include <phosphor-logging/log.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053017#include <stdexcept>
William A. Kennington IIId81a0982019-02-01 21:10:27 -080018#include <string_view>
Patrick Venture189d44e2018-07-09 12:30:59 -070019#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta233524c2017-05-27 11:47:31 +053020
21namespace phosphor
22{
23namespace network
24{
25namespace route
26{
27
28using namespace phosphor::logging;
29using namespace sdbusplus::xyz::openbmc_project::Common::Error;
30
31Table::Table()
32{
33 try
34 {
35 getRoutes();
36 }
37 catch (InternalFailure& e)
38 {
39 commit<InternalFailure>();
40 }
Ratan Gupta233524c2017-05-27 11:47:31 +053041}
42
Gunnar Mills57d9c502018-09-14 14:42:34 -050043int Table::readNetLinkSock(int sockFd, std::array<char, BUFSIZE>& buf)
Ratan Gupta233524c2017-05-27 11:47:31 +053044{
45 struct nlmsghdr* nlHdr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -050046 int readLen{};
47 int msgLen{};
Ratan Gupta233524c2017-05-27 11:47:31 +053048 uint8_t seqNum = 1;
49 uint8_t pID = getpid();
50 char* bufPtr = buf.data();
51
52 do
53 {
Gunnar Millsd75f0492017-10-25 20:33:32 -050054 // Receive response from the kernel
Ratan Gupta233524c2017-05-27 11:47:31 +053055 if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0)
56 {
57 auto error = errno;
58 log<level::ERR>("Socket recv failed:",
Gunnar Mills57d9c502018-09-14 14:42:34 -050059 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053060 elog<InternalFailure>();
Ratan Gupta233524c2017-05-27 11:47:31 +053061 }
62
63 nlHdr = reinterpret_cast<nlmsghdr*>(bufPtr);
64
65 // Check if the header is valid
66
Gunnar Mills57d9c502018-09-14 14:42:34 -050067 if ((NLMSG_OK(nlHdr, readLen) == 0) ||
68 (nlHdr->nlmsg_type == NLMSG_ERROR))
Ratan Gupta233524c2017-05-27 11:47:31 +053069 {
70
71 auto error = errno;
72 log<level::ERR>("Error validating header",
Gunnar Mills57d9c502018-09-14 14:42:34 -050073 entry("NLMSGTYPE=%d", nlHdr->nlmsg_type),
74 entry("ERROR=%s", strerror(error)));
Ratan Gupta233524c2017-05-27 11:47:31 +053075 elog<InternalFailure>();
76 }
77
78 // Check if the its the last message
79 if (nlHdr->nlmsg_type == NLMSG_DONE)
80 {
81 break;
82 }
83 else
84 {
85 // Else move the pointer to buffer appropriately
86 bufPtr += readLen;
87 msgLen += readLen;
88 }
89
90 // Check if its a multi part message
91 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)
92 {
93 break;
94 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050095 } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pID));
Ratan Gupta233524c2017-05-27 11:47:31 +053096 return msgLen;
97}
98
99void Table::parseRoutes(const nlmsghdr* nlHdr)
100{
101 rtmsg* rtMsg = nullptr;
102 rtattr* rtAttr = nullptr;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500103 int rtLen{};
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800104 std::optional<InAddrAny> dstAddr;
105 std::optional<InAddrAny> gateWayAddr;
Ratan Gupta233524c2017-05-27 11:47:31 +0530106 char ifName[IF_NAMESIZE] = {};
107
108 rtMsg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nlHdr));
109
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800110 // If the route is not for AF_INET{,6} or does not belong to main routing
111 // table then return.
112 if ((rtMsg->rtm_family != AF_INET && rtMsg->rtm_family != AF_INET6) ||
113 rtMsg->rtm_table != RT_TABLE_MAIN)
Ratan Gupta233524c2017-05-27 11:47:31 +0530114 {
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 {
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800125 std::string_view attrData(reinterpret_cast<char*>(RTA_DATA(rtAttr)),
126 RTA_PAYLOAD(rtAttr));
Ratan Gupta233524c2017-05-27 11:47:31 +0530127 switch (rtAttr->rta_type)
128 {
129 case RTA_OIF:
Gunnar Mills57d9c502018-09-14 14:42:34 -0500130 if_indextoname(*reinterpret_cast<int*>(RTA_DATA(rtAttr)),
131 ifName);
Ratan Gupta233524c2017-05-27 11:47:31 +0530132 break;
133 case RTA_GATEWAY:
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800134 gateWayAddr = addrFromBuf(rtMsg->rtm_family, attrData);
Ratan Gupta233524c2017-05-27 11:47:31 +0530135 break;
136 case RTA_DST:
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800137 dstAddr = addrFromBuf(rtMsg->rtm_family, attrData);
Ratan Gupta233524c2017-05-27 11:47:31 +0530138 break;
139 }
140 }
141
142 std::string dstStr;
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800143 if (dstAddr)
Ratan Gupta233524c2017-05-27 11:47:31 +0530144 {
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800145 dstStr = toString(*dstAddr);
Ratan Gupta233524c2017-05-27 11:47:31 +0530146 }
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800147 std::string gatewayStr;
148 if (gateWayAddr)
149 {
150 gatewayStr = toString(*gateWayAddr);
151 }
152 if (!dstAddr && gateWayAddr)
153 {
154 if (rtMsg->rtm_family == AF_INET)
155 {
156 defaultGateway = gatewayStr;
157 }
William A. Kennington IIId3c249c2019-02-01 21:12:02 -0800158 else if (rtMsg->rtm_family == AF_INET6)
159 {
160 defaultGateway6 = gatewayStr;
161 }
William A. Kennington IIId81a0982019-02-01 21:10:27 -0800162 }
Ratan Gupta233524c2017-05-27 11:47:31 +0530163
164 Entry route(dstStr, gatewayStr, ifName);
Ratan Gupta4a5f08a2018-05-04 17:23:16 +0530165 // if there is already existing route for this network
166 // then ignore the next one as it would not be used by the
167 // routing policy
168 // So don't update the route entry for the network for which
169 // there is already a route exist.
170 if (routeList.find(dstStr) == routeList.end())
171 {
172 routeList.emplace(std::make_pair(dstStr, std::move(route)));
173 }
Ratan Gupta233524c2017-05-27 11:47:31 +0530174}
175
176Map Table::getRoutes()
177{
178 nlmsghdr* nlMsg = nullptr;
179 std::array<char, BUFSIZE> msgBuf = {0};
180
181 int sock = -1;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500182 int len{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530183
Gunnar Mills57d9c502018-09-14 14:42:34 -0500184 uint8_t msgSeq{0};
Ratan Gupta233524c2017-05-27 11:47:31 +0530185
186 // Create Socket
187 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
188 {
189 auto error = errno;
Gunnar Millsd75f0492017-10-25 20:33:32 -0500190 log<level::ERR>("Error occurred during socket creation",
Ratan Gupta233524c2017-05-27 11:47:31 +0530191 entry("ERRNO=%s", strerror(error)));
192 elog<InternalFailure>();
193 }
194
195 phosphor::Descriptor smartSock(sock);
196 sock = -1;
197
198 // point the header and the msg structure pointers into the buffer.
199 nlMsg = reinterpret_cast<nlmsghdr*>(msgBuf.data());
200 // Length of message
201 nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
202 // Get the routes from kernel routing table
Gunnar Mills57d9c502018-09-14 14:42:34 -0500203 nlMsg->nlmsg_type = RTM_GETROUTE;
Ratan Gupta233524c2017-05-27 11:47:31 +0530204 // The message is a request for dump
205 nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
206
207 nlMsg->nlmsg_seq = msgSeq;
208 nlMsg->nlmsg_pid = getpid();
209
210 // Send the request
211 if (send(smartSock(), nlMsg, nlMsg->nlmsg_len, 0) < 0)
212 {
213 auto error = errno;
214 log<level::ERR>("Error occurred during send on netlink socket",
215 entry("ERRNO=%s", strerror(error)));
216 elog<InternalFailure>();
217 }
218
219 // Read the response
220 len = readNetLinkSock(smartSock(), msgBuf);
221
222 // Parse and print the response
223 for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len))
224 {
225 parseRoutes(nlMsg);
226 }
227 return routeList;
228}
229
Gunnar Mills57d9c502018-09-14 14:42:34 -0500230} // namespace route
231} // namespace network
232} // namespace phosphor