1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "TcpSocketMonitor"
18
19 #include <iomanip>
20 #include <thread>
21 #include <vector>
22
23 #include <arpa/inet.h>
24 #include <netinet/tcp.h>
25 #include <linux/tcp.h>
26
27 #include "Controllers.h"
28 #include "DumpWriter.h"
29 #include "SockDiag.h"
30 #include "TcpSocketMonitor.h"
31
32 namespace android {
33 namespace net {
34
35 using std::chrono::duration_cast;
36 using std::chrono::steady_clock;
37
getTcpStateName(int t)38 constexpr const char* getTcpStateName(int t) {
39 switch (t) {
40 case TCP_ESTABLISHED:
41 return "ESTABLISHED";
42 case TCP_SYN_SENT:
43 return "SYN-SENT";
44 case TCP_SYN_RECV:
45 return "SYN-RECV";
46 case TCP_FIN_WAIT1:
47 return "FIN-WAIT-1";
48 case TCP_FIN_WAIT2:
49 return "FIN-WAIT-2";
50 case TCP_TIME_WAIT:
51 return "TIME-WAIT";
52 case TCP_CLOSE:
53 return "CLOSE";
54 case TCP_CLOSE_WAIT:
55 return "CLOSE-WAIT";
56 case TCP_LAST_ACK:
57 return "LAST-ACK";
58 case TCP_LISTEN:
59 return "LISTEN";
60 case TCP_CLOSING:
61 return "CLOSING";
62 default:
63 return "UNKNOWN";
64 }
65 }
66
67 // Helper macro for reading fields into struct tcp_info and handling different struct tcp_info
68 // versions in the kernel.
69 #define TCPINFO_GET(ptr, fld, len, zero) \
70 (((ptr) != nullptr && (offsetof(struct tcp_info, fld) + sizeof((ptr)->fld)) < len) ? \
71 (ptr)->fld : zero)
72
tcpInfoPrint(DumpWriter & dw,Fwmark mark,const struct inet_diag_msg * sockinfo,const struct tcp_info * tcpinfo,uint32_t tcpinfoLen)73 static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
74 const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
75 char saddr[INET6_ADDRSTRLEN] = {};
76 char daddr[INET6_ADDRSTRLEN] = {};
77 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
78 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
79
80 dw.println(
81 "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
82 "rtt=%gms sent=%u lost=%u",
83 mark.netId,
84 sockinfo->idiag_uid,
85 mark.intValue,
86 saddr,
87 daddr,
88 ntohs(sockinfo->id.idiag_sport),
89 ntohs(sockinfo->id.idiag_dport),
90 getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
91 TCPINFO_GET(tcpinfo, tcpi_rtt, tcpinfoLen, 0) / 1000.0,
92 TCPINFO_GET(tcpinfo, tcpi_segs_out, tcpinfoLen, 0),
93 TCPINFO_GET(tcpinfo, tcpi_lost, tcpinfoLen, 0));
94 }
95
96 const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
97 const milliseconds TcpSocketMonitor::kDefaultPollingInterval = milliseconds(30000);
98
dump(DumpWriter & dw)99 void TcpSocketMonitor::dump(DumpWriter& dw) {
100 std::lock_guard<std::mutex> guard(mLock);
101
102 dw.println("TcpSocketMonitor");
103 dw.incIndent();
104
105 const auto now = steady_clock::now();
106 const auto d = duration_cast<milliseconds>(now - mLastPoll);
107 dw.println("running=%d, suspended=%d, last poll %lld ms ago",
108 mIsRunning, mIsSuspended, d.count());
109
110 if (!mNetworkStats.empty()) {
111 dw.blankline();
112 dw.println("Network stats:");
113 for (auto const& stats : mNetworkStats) {
114 if (stats.second.nSockets == 0) {
115 continue;
116 }
117 dw.println("netId=%d sent=%d lost=%d rttMs=%gms sentAckDiff=%gms",
118 stats.first,
119 stats.second.sent,
120 stats.second.lost,
121 stats.second.rttUs / 1000.0 / stats.second.nSockets,
122 stats.second.sentAckDiffMs / stats.second.nSockets);
123 }
124 }
125
126 if (!mSocketEntries.empty()) {
127 dw.blankline();
128 dw.println("Socket entries:");
129 for (auto const& stats : mSocketEntries) {
130 dw.println("netId=%u uid=%u cookie=%ld",
131 stats.second.mark.netId, stats.second.uid, stats.first);
132 }
133 }
134
135 SockDiag sd;
136 if (sd.open()) {
137 dw.blankline();
138 dw.println("Current socket dump:");
139 const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
140 const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
141 tcpInfoPrint(dw, mark, sockinfo, tcpinfo, tcpinfoLen);
142 };
143
144 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
145 ALOGE("Failed to dump TCP socket info: %s", strerror(-ret));
146 }
147 } else {
148 ALOGE("Error opening sock diag for dumping TCP socket info");
149 }
150
151 dw.decIndent();
152 }
153
setPollingInterval(milliseconds nextSleepDurationMs)154 void TcpSocketMonitor::setPollingInterval(milliseconds nextSleepDurationMs) {
155 std::lock_guard<std::mutex> guard(mLock);
156
157 mNextSleepDurationMs = nextSleepDurationMs;
158
159 ALOGD("tcpinfo polling interval set to %lld ms", mNextSleepDurationMs.count());
160 }
161
resumePolling()162 void TcpSocketMonitor::resumePolling() {
163 bool wasSuspended;
164 {
165 std::lock_guard<std::mutex> guard(mLock);
166
167 wasSuspended = mIsSuspended;
168 mIsSuspended = false;
169 ALOGD("resuming tcpinfo polling (interval=%lldms)", mNextSleepDurationMs.count());
170 }
171
172 if (wasSuspended) {
173 mCv.notify_all();
174 }
175 }
176
suspendPolling()177 void TcpSocketMonitor::suspendPolling() {
178 std::lock_guard<std::mutex> guard(mLock);
179
180 bool wasSuspended = mIsSuspended;
181 mIsSuspended = true;
182 ALOGD("suspending tcpinfo polling");
183
184 if (!wasSuspended) {
185 mSocketEntries.clear();
186 }
187 }
188
poll()189 void TcpSocketMonitor::poll() {
190 std::lock_guard<std::mutex> guard(mLock);
191
192 if (mIsSuspended) {
193 return;
194 }
195
196 SockDiag sd;
197 if (!sd.open()) {
198 ALOGE("Error opening sock diag for polling TCP socket info");
199 return;
200 }
201
202 const auto now = steady_clock::now();
203 const auto tcpInfoReader = [this, now](Fwmark mark, const struct inet_diag_msg *sockinfo,
204 const struct tcp_info *tcpinfo,
205 uint32_t tcpinfoLen) NO_THREAD_SAFETY_ANALYSIS {
206 if (sockinfo == nullptr || tcpinfo == nullptr || tcpinfoLen == 0 || mark.intValue == 0) {
207 return;
208 }
209 updateSocketStats(now, mark, sockinfo, tcpinfo, tcpinfoLen);
210 };
211
212 // Reset mNetworkStats
213 mNetworkStats.clear();
214
215 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
216 ALOGE("Failed to poll TCP socket info: %s", strerror(-ret));
217 return;
218 }
219
220 // Remove any SocketEntry not updated
221 for (auto it = mSocketEntries.cbegin(); it != mSocketEntries.cend();) {
222 if (it->second.lastUpdate < now) {
223 it = mSocketEntries.erase(it);
224 } else {
225 it++;
226 }
227 }
228
229 const auto listener = gCtls->eventReporter.getNetdEventListener();
230 if (listener != nullptr) {
231 std::vector<int> netIds;
232 std::vector<int> sentPackets;
233 std::vector<int> lostPackets;
234 std::vector<int> rtts;
235 std::vector<int> sentAckDiffs;
236 for (auto const& stats : mNetworkStats) {
237 int32_t nSockets = stats.second.nSockets;
238 if (nSockets == 0) {
239 continue;
240 }
241 netIds.push_back(stats.first);
242 sentPackets.push_back(stats.second.sent);
243 lostPackets.push_back(stats.second.lost);
244 rtts.push_back(stats.second.rttUs / nSockets);
245 sentAckDiffs.push_back(stats.second.sentAckDiffMs / nSockets);
246 }
247 listener->onTcpSocketStatsEvent(netIds, sentPackets, lostPackets, rtts, sentAckDiffs);
248 }
249
250 mLastPoll = now;
251 }
252
waitForNextPoll()253 void TcpSocketMonitor::waitForNextPoll() {
254 bool isSuspended;
255 milliseconds nextSleepDurationMs;
256 {
257 std::lock_guard<std::mutex> guard(mLock);
258 isSuspended = mIsSuspended;
259 nextSleepDurationMs= mNextSleepDurationMs;
260 }
261
262 std::unique_lock<std::mutex> ul(mLock);
263 if (isSuspended) {
264 mCv.wait(ul);
265 } else {
266 mCv.wait_for(ul, nextSleepDurationMs);
267 }
268 }
269
isRunning()270 bool TcpSocketMonitor::isRunning() {
271 std::lock_guard<std::mutex> guard(mLock);
272 return mIsRunning;
273 }
274
updateSocketStats(time_point now,Fwmark mark,const struct inet_diag_msg * sockinfo,const struct tcp_info * tcpinfo,uint32_t tcpinfoLen)275 void TcpSocketMonitor::updateSocketStats(time_point now, Fwmark mark,
276 const struct inet_diag_msg *sockinfo,
277 const struct tcp_info *tcpinfo,
278 uint32_t tcpinfoLen) NO_THREAD_SAFETY_ANALYSIS {
279 int32_t lastAck = TCPINFO_GET(tcpinfo, tcpi_last_ack_recv, tcpinfoLen, 0);
280 int32_t lastSent = TCPINFO_GET(tcpinfo, tcpi_last_data_sent, tcpinfoLen, 0);
281 TcpStats diff = {
282 .sent = TCPINFO_GET(tcpinfo, tcpi_segs_out, tcpinfoLen, 0),
283 .lost = TCPINFO_GET(tcpinfo, tcpi_lost, tcpinfoLen, 0),
284 .rttUs = TCPINFO_GET(tcpinfo, tcpi_rtt, tcpinfoLen, 0),
285 .sentAckDiffMs = lastAck - lastSent,
286 .nSockets = 1,
287 };
288
289 {
290 // Update socket stats with the newest entry, computing the diff w.r.t the previous entry.
291 const uint64_t cookie = (static_cast<uint64_t>(sockinfo->id.idiag_cookie[0]) << 32)
292 | static_cast<uint64_t>(sockinfo->id.idiag_cookie[1]);
293 const SocketEntry previous = mSocketEntries[cookie];
294 mSocketEntries[cookie] = {
295 .sent = diff.sent,
296 .lost = diff.lost,
297 .lastUpdate = now,
298 .mark = mark,
299 .uid = sockinfo->idiag_uid,
300 };
301
302 diff.sent -= previous.sent;
303 diff.lost -= previous.lost;
304 }
305
306 {
307 // Aggregate the diff per network id.
308 auto& stats = mNetworkStats[mark.netId];
309 stats.sent += diff.sent;
310 stats.lost += diff.lost;
311 stats.rttUs += diff.rttUs;
312 stats.sentAckDiffMs += diff.sentAckDiffMs;
313 stats.nSockets += diff.nSockets;
314 }
315 }
316
TcpSocketMonitor()317 TcpSocketMonitor::TcpSocketMonitor() {
318 std::lock_guard<std::mutex> guard(mLock);
319
320 mNextSleepDurationMs = kDefaultPollingInterval;
321 mIsRunning = true;
322 mIsSuspended = true;
323 mPollingThread = std::thread([this] {
324 (void) this;
325 while (isRunning()) {
326 poll();
327 waitForNextPoll();
328 }
329 });
330 }
331
~TcpSocketMonitor()332 TcpSocketMonitor::~TcpSocketMonitor() {
333 {
334 std::lock_guard<std::mutex> guard(mLock);
335 mIsRunning = false;
336 mIsSuspended = true;
337 }
338 mCv.notify_all();
339 mPollingThread.join();
340 }
341
342 } // namespace net
343 } // namespace android
344