Home | History | Annotate | Download | only in server
      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