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 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 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 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 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 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 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 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 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 270 bool TcpSocketMonitor::isRunning() { 271 std::lock_guard<std::mutex> guard(mLock); 272 return mIsRunning; 273 } 274 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 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 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