LCOV - code coverage report
Current view: top level - legacy/ascend910/framework/cluster_maintenance/detect/detect_connect_anomalies - detect_connect_anomalies.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 68.4 % 462 316
Test Date: 2026-08-04 10:52:23 Functions: 84.0 % 25 21

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #include <chrono>
      12              : #include <thread>
      13              : #include "hccl_common.h"
      14              : #include "hccl_socket.h"
      15              : #include "env_config.h"
      16              : #include "externalinput_pub.h"
      17              : #include "detect_connect_anomalies.h"
      18              : 
      19              : namespace hccl {
      20         1079 : DetectConnectionAnomalies &DetectConnectionAnomalies::GetInstance(s32 deviceLogicID)
      21              : {
      22         1924 :     static DetectConnectionAnomalies dca[MAX_MODULE_DEVICE_NUM];
      23         1079 :     if (static_cast<u32>(deviceLogicID) >= MAX_MODULE_DEVICE_NUM) {
      24          273 :         HCCL_WARNING("[DetectConnectionAnomalies][GetInstance]deviceLogicID[%d] is invalid", deviceLogicID);
      25          273 :         return dca[0];
      26              :     }
      27          806 :     return dca[deviceLogicID];
      28              : }
      29              : 
      30              : // 创建单例,保存所有RankInfoList中的Ip地址
      31          196 : void DetectConnectionAnomalies::Init(std::vector<RankInfo> &rankInfos, bool isNeedNic)
      32              : {
      33          196 :     if (isNeedNic) {
      34            0 :         isNeedNic_ =  isNeedNic;
      35              :     }
      36              :     // 直接用set保存,省掉查重
      37          196 :     int ref = initRef_.Ref();
      38          196 :     HCCL_INFO("DetectConnectionAnomalies[Init] initRef[%d]", ref);
      39         1135 :     for (auto &rankInfo : rankInfos) {
      40          940 :         if (!rankInfo.nicIp[0].IsInvalid()) {
      41          941 :             uniqueIps_.insert(rankInfo.nicIp[0]);
      42              :         }
      43              : 
      44          945 :         if (!rankInfo.deviceVnicIp.IsInvalid()) {
      45          582 :             uniqueIps_.insert(rankInfo.deviceVnicIp);
      46              :         }
      47              :     }
      48          196 :     return;
      49              : }
      50              : 
      51              : // 添加ipQueue
      52           38 : void DetectConnectionAnomalies::AddIpQueue(RankInfo &localRankInfo, RankInfo &remoteRankInfo, NicType nicType,
      53              :     s32 deviceLogicId)
      54              : {
      55              :     // 检查是否需要进行连接异常检测
      56           38 :     if (GetExternalInputDfsConnectionFaultDetectionTime() == 0 || !threadExit_) {
      57           38 :         HCCL_RUN_INFO("[Add][IpQueue]GetExternalInputDfsConnectionFaultDetectionTime is 0, no need to detect");
      58          265 :         RPT_INPUT_ERR(true, "EI0006", std::vector<std::string>({"reason"}), \
      59              :         std::vector<std::string>({GET_SOCKET_TIMEOUT_REASON_CLOSE_DETECT}));
      60           38 :         return;
      61              :     }
      62              : 
      63              :     // 检查设备类型是否支持
      64            0 :     if (localRankInfo.deviceType != DevType::DEV_TYPE_910_93 && localRankInfo.deviceType != DevType::DEV_TYPE_910B) {
      65            0 :         HCCL_WARNING("[AddIpQueue] not support deviceType[%d]", localRankInfo.deviceType);
      66            0 :         RPT_INPUT_ERR(true, "EI0006", std::vector<std::string>({"reason"}), \
      67              :         std::vector<std::string>({GET_SOCKET_TIMEOUT_REASON_CLOSE_DETECT}));
      68            0 :         return;
      69              :     }
      70              : 
      71              :     // 检查是否需要进行连接异常检测
      72            0 :     HcclIpAddress localIp = (nicType == NicType::VNIC_TYPE) ? localRankInfo.deviceVnicIp : localRankInfo.nicIp[0];
      73            0 :     HcclIpAddress remoteIp = (nicType == NicType::DEVICE_NIC_TYPE || nicType == NicType::HOST_NIC_TYPE) ?
      74            0 :         remoteRankInfo.nicIp[0] : remoteRankInfo.deviceVnicIp;
      75            0 :     if (localIp.IsInvalid() || remoteIp.IsInvalid()) {
      76            0 :         return;
      77              :     }
      78              : 
      79              :     // 多线程访问ipQueue需要加锁
      80            0 :     Detect();
      81            0 :     std::unique_lock<std::mutex> lock(ipNictypeQueueMutex_);
      82            0 :     ErrInfo errInfo;
      83            0 :     auto ip = ipMap_.find(remoteIp);
      84            0 :     if (ip == ipMap_.end()) {
      85            0 :         ipMap_.insert(std::make_pair(remoteIp, localIp));
      86            0 :         HCCL_INFO("[Add][IpQueue]localIp[%s], remoteIp[%s], nicType[%d], deviceLogicId[%d]", 
      87              :             localIp.GetReadableAddress(), remoteIp.GetReadableAddress(), nicType, deviceLogicId);
      88            0 :         errInfo.localRankInfo = localRankInfo;
      89            0 :         errInfo.remoteRankInfo = remoteRankInfo;
      90            0 :         errInfo.nicType = nicType;
      91            0 :         errInfo.deviceLogicId = deviceLogicId;
      92            0 :         ipNictypeQueue_.push(errInfo); // 记录报错卡信息
      93              :     }
      94            0 :     lock.unlock();
      95            0 :     WaitForDectect();
      96            0 :     HCCL_INFO("[Add][IpQueue]ipNictypeQueue size[%d]", ipNictypeQueue_.size());
      97            0 :     return;
      98           38 : }
      99            0 : HcclResult DetectConnectionAnomalies::WaitForDectect()
     100              : {
     101              :     // 计算等待时间
     102            0 :     auto waitTime = std::chrono::seconds(GetExternalInputDfsConnectionFaultDetectionTime()) +
     103            0 :         std::chrono::seconds(broadCastTime);
     104            0 :     std::unique_lock<std::mutex> timelock(time_mutex);
     105            0 :     startTime = std::chrono::steady_clock::now(); // 刷新时间
     106            0 :     std::chrono::steady_clock::time_point localStartTime = startTime;
     107            0 :     timelock.unlock();
     108              : 
     109            0 :     while (threadExit_ && (std::chrono::steady_clock::now() - localStartTime) <= waitTime) {
     110            0 :         std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 每次休眠100毫秒
     111            0 :         timelock.lock();
     112            0 :         localStartTime = startTime;
     113            0 :         timelock.unlock();
     114              :     }
     115              :     // 通过锁只进入一次
     116            0 :     std::lock_guard<std::mutex> printlock(print_mutex);
     117            0 :     if (!isPrint_) {
     118            0 :         ProcessDetectionResults();
     119              :     }
     120            0 :     isPrint_ = true;
     121            0 :     return HCCL_SUCCESS;
     122            0 : }
     123              : 
     124            4 : std::string DetectConnectionAnomalies::BuildGroupedDetectMessage()
     125              : {
     126            4 :     std::ostringstream result;
     127              :     // key: <srcServer, srcDevice>  value: <dstServer, dstDeviceList>
     128            4 :     std::map<std::pair<std::string, s32>, std::map<std::string, std::vector<s32>>> summary;
     129              :     // 聚合deviceID
     130           10 :     for (const auto &item : recvErrorInfoMap_) {
     131            6 :         const DetectInfo &info = item.second;
     132           18 :         summary[{info.localServerId, info.localDeviceId}][info.remoteServerId].push_back(info.remoteDeviceId);
     133              :     }
     134            4 :     bool firstMsg = true;
     135            8 :     for (auto &srcGroup : summary) {
     136            4 :         const std::string &srcServer = srcGroup.first.first;
     137            4 :         s32 srcDevice = srcGroup.first.second;
     138            8 :         for (auto &dstGroup : srcGroup.second) {
     139            4 :             auto &devices = dstGroup.second;
     140            4 :             std::sort(devices.begin(), devices.end());
     141            4 :             devices.erase(std::unique(devices.begin(), devices.end()), devices.end());
     142            4 :             std::ostringstream deviceList;
     143            4 :             deviceList << "[";
     144            9 :             for (size_t i = 0; i < devices.size(); ++i) {
     145            5 :                 if (i != 0) {
     146            1 :                     deviceList << ",";
     147              :                 }
     148            5 :                 deviceList << devices[i];
     149              :             }
     150            4 :             deviceList << "]";
     151            4 :             if (!firstMsg) {
     152            1 :                 result << "\n";
     153              :             }
     154            4 :             firstMsg = false;
     155              :             result << "This node (server " << srcServer
     156            4 :                 << ", device ID " << srcDevice
     157              :                 << ") detects that srcRank (server " << srcServer
     158            4 :                 << ", device ID " << srcDevice
     159            4 :                 << ") fails to connect to dstRank (server " << dstGroup.first
     160            4 :                 << ", device ID " << deviceList.str()
     161            4 :                 << "). Continue to analyze the fault based on the logs of srcRank and dstRank.";
     162            4 :         }
     163              :     }
     164            8 :     return result.str();
     165            4 : }
     166              : 
     167            0 : HcclResult DetectConnectionAnomalies::ProcessDetectionResults()
     168              : {
     169            0 :     std::string errMsg;
     170            0 :     HCCL_ERROR("-------------------CONNECT TIMEOUT DETECT RESULT-----------------------");
     171            0 :     if (!recvErrorInfoMap_.empty()) {
     172            0 :         errMsg = BuildGroupedDetectMessage();
     173            0 :         HCCL_ERROR("%s", errMsg.c_str());
     174            0 :         HCCL_ERROR("%s", GET_SOCKET_TIMEOUT_REASON_WITH_EVENT.c_str());
     175            0 :         errMsg += "\n" + GET_SOCKET_TIMEOUT_REASON_WITH_EVENT;
     176              :     } else {
     177              :         errMsg ="This node detects no exception event. The possible cause is that the behaviors of different ranks are inconsistent. "
     178            0 :             "The possible causes are as follows:";
     179            0 :         HCCL_ERROR("%s", errMsg.c_str());
     180            0 :         HCCL_ERROR("%s", GET_SOCKET_TIMEOUT_REASON_WITHOUT_EVENT.c_str());
     181            0 :         errMsg += "\n" + GET_SOCKET_TIMEOUT_REASON_WITHOUT_EVENT;
     182              :     }
     183              : 
     184            0 :     HCCL_ERROR("----------------------------------------------------------------------");
     185            0 :     RPT_INPUT_ERR(true, "EI0006", std::vector<std::string>{"reason"}, std::vector<std::string>{errMsg});
     186            0 :     return HCCL_SUCCESS;
     187            0 : }
     188              : // 检测连接异常
     189           11 : HcclResult DetectConnectionAnomalies::Detect()
     190              : {
     191           11 :     std::unique_lock<std::mutex> lock(detectThreadMutex_);
     192           11 :     if (!isInitThread_ && threadExit_) {
     193              :         // 初始化线程,轮询ipNictypeQueue_
     194            4 :         getIpNictypeQueue_.reset(new (std::nothrow) std::thread(&DetectConnectionAnomalies::DetectMonitor, this));
     195            4 :         CHK_SMART_PTR_NULL(getIpNictypeQueue_);
     196            4 :         isInitThread_  = true;
     197              :     }
     198           11 :     lock.unlock();
     199           11 :     return HCCL_SUCCESS;
     200           11 : }
     201              : 
     202              : 
     203            4 : void DetectConnectionAnomalies::DetectMonitor()
     204              : {
     205            7 :     while (threadExit_) {
     206            3 :         GetIpQueue();
     207            3 :         std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 每次休眠100毫秒
     208              :     }
     209            4 :     return;
     210              : }
     211              : // 心跳线程调用
     212            3 : HcclResult DetectConnectionAnomalies::GetIpQueue()
     213              : {
     214            3 :     if (ipNictypeQueue_.empty()) {
     215            3 :         return HCCL_SUCCESS;
     216              :     }
     217              : 
     218            0 :     HCCL_RUN_INFO("[GetIpQueue]ipNictypeQueue_ size[%d], start to detect", ipNictypeQueue_.size());
     219            0 :     std::unique_lock<std::mutex> lock(ipNictypeQueueMutex_);
     220            0 :     while (!ipNictypeQueue_.empty() && threadExit_) {
     221            0 :         auto& errInfo = ipNictypeQueue_.front();
     222            0 :         if (CreateServers(errInfo) != HCCL_SUCCESS ||
     223            0 :             CreateClients(errInfo, linkClientThreads_) != HCCL_SUCCESS) {
     224            0 :             ipNictypeQueue_.pop();
     225            0 :             HCCL_ERROR("[GetIpQueue]CreateServers or CreateClients fail");
     226            0 :             return HCCL_E_INTERNAL;
     227              :         }
     228            0 :         ipNictypeQueue_.pop();
     229              :     }
     230            0 :     HCCL_INFO("[GetIpQueue] completed[%d]", ipNictypeQueue_.size());
     231            0 :     lock.unlock();
     232            0 :     return HCCL_SUCCESS;
     233            0 : }
     234              : 
     235            1 : HcclResult DetectConnectionAnomalies::CreateDetectVnicLinks(struct ErrInfo  errInfo)
     236              : {
     237            1 :     SetThreadName("Hccl_Detect_vnic");
     238            1 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     239            1 :         hrtSetDevice(errInfo.deviceLogicId);
     240              :     }
     241            1 :     CHK_RET(HcclNetOpenDev(&vnicCtx_, NicType::VNIC_TYPE, errInfo.localRankInfo.devicePhyId,
     242              :         errInfo.deviceLogicId, errInfo.localRankInfo.deviceVnicIp));
     243            1 :     CHK_PTR_NULL(vnicCtx_);
     244            1 :     std::string tag = GetTag(errInfo.localRankInfo.deviceVnicIp);
     245            1 :     u32 port = (errInfo.localRankInfo.deviceVnicPort== HCCL_INVALID_PORT) ? HETEROG_CCL_PORT : port;
     246              : 
     247              :     // 创建vnic socket服务端
     248            1 :     EXCEPTION_CATCH((vnicSocket_ = std::make_shared<HcclSocket>(vnicCtx_, port)), return HCCL_E_PTR);
     249            1 :     HCCL_RUN_INFO("[CreateDetectVnicLinks]tag[%s], localIpAddr[%s], remoteIpAddr[%u], port[%u]", tag.c_str(),
     250              :         errInfo.localRankInfo.deviceVnicIp.GetReadableIP(),  errInfo.remoteRankInfo.deviceVnicIp.GetReadableIP(), port);
     251              : 
     252            1 :     CHK_RET(vnicSocket_->Init());
     253            1 :     CHK_RET(vnicSocket_->Listen());
     254            1 :     CHK_RET(AddWhiteList(vnicSocket_, NicType::VNIC_TYPE, tag));; // 添加白名单
     255            1 :     HCCL_INFO("[CreateDetectVnicLinks]AddWhiteList finished");
     256              : 
     257            1 :     u32 acceptTimeOut = 1; // accept 超时1s
     258            1 :     std::shared_ptr<HcclSocket> acceptSuccessSocket;
     259            1 :     auto detectTimeOut = std::chrono::seconds(GetExternalInputDfsConnectionFaultDetectionTime());
     260            1 :     startTime = std::chrono::steady_clock::now();
     261              :     HcclResult ret;
     262           11 :     while (threadExit_ && (std::chrono::steady_clock::now() - startTime) < std::chrono::seconds(detectTimeOut)) {
     263           10 :         ret = vnicSocket_->Accept(tag, acceptSuccessSocket, acceptTimeOut);
     264           10 :         if (ret == HCCL_SUCCESS) {
     265            0 :             HCCL_INFO("[CreateDetectVnicLinks]accept success, localIpAddr[%s], acceptSuccessSocket[%p]",
     266              :                 errInfo.localRankInfo.deviceVnicIp.GetReadableIP(), acceptSuccessSocket.get());
     267            0 :             listenVnicVec_.push_back(acceptSuccessSocket);  // 保存accept成功的socket
     268              :         }
     269           10 :         usleep(ACCEPT_TIME_OF_USLEEP); // 休眠100毫秒
     270              :     }
     271              :     // 循环发送检测信息
     272            1 :     startTime = std::chrono::steady_clock::now();
     273           11 :     while (threadExit_ && (std::chrono::steady_clock::now() - startTime) <= std::chrono::seconds(broadCastTime)) {
     274           10 :         std::unique_lock<std::mutex> lock(readRecvErrtInfo_);
     275           20 :         for (auto &recvError : recvErrorInfoMap_) {
     276           10 :             auto it = sendErrorInfoMap_.find(recvError.first);
     277           10 :             if (it != sendErrorInfoMap_.end() && !sendErrorInfoMap_[recvError.first].isSendVnic) {
     278            2 :                 for (auto &socket : listenVnicVec_) {
     279            1 :                     CHK_RET(socket->Send(&recvError.second, sizeof(recvError.second)));
     280              :                 }
     281              :                 // 给所有socket都发送完成后,才标记发送完成
     282            1 :                 sendErrorInfoMap_[recvError.first].isSendVnic = true;
     283              :             }
     284              :         }
     285           10 :         lock.unlock();
     286           10 :         usleep(ACCEPT_TIME_OF_USLEEP); // 休眠1毫秒,将锁释放给IRecv
     287           10 :     }
     288            1 :     std::unique_lock<std::mutex> lock(whiteListMutex_);
     289            1 :     CHK_RET(DelWhiteList(errInfo.localRankInfo.deviceVnicIp, vnicWhiteListInfosVec_, vnicSocket_)); // 删除白名单
     290            1 :     lock.unlock();
     291            1 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     292            1 :         hrtResetDevice(errInfo.deviceLogicId);
     293              :     }
     294            1 :     HCCL_INFO("[CreateDetectVnicLinks] completed");
     295            1 :     return HCCL_SUCCESS;
     296            1 : }
     297              : 
     298            2 : HcclResult DetectConnectionAnomalies::CreateDetectNicLinks(struct ErrInfo errInfo)
     299              : {
     300            2 :     SetThreadName("Hccl_Detect_Nic");
     301            2 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     302            2 :         hrtSetDevice(errInfo.deviceLogicId);
     303              :     }
     304            2 :     CHK_RET(HcclNetOpenDev(&nicCtx_, NicType::DEVICE_NIC_TYPE, errInfo.localRankInfo.devicePhyId,
     305              :         errInfo.deviceLogicId, errInfo.localRankInfo.nicIp[0]));
     306            2 :     CHK_PTR_NULL(nicCtx_);
     307            2 :     std::string tag = GetTag(errInfo.localRankInfo.nicIp[0]);
     308              : 
     309            2 :     u32 port = (errInfo.localRankInfo.deviceNicPort == HCCL_INVALID_PORT) ? HETEROG_CCL_PORT : port;
     310            2 :     EXCEPTION_CATCH((nicSocket_ = std::make_shared<HcclSocket>(nicCtx_, port)), return HCCL_E_PTR);
     311              : 
     312            2 :     HCCL_RUN_INFO("[CreateDetectNicLinks]tag[%s], localIp[%s], remoteIp[%u], port[%u]", tag.c_str(),
     313              :         errInfo.localRankInfo.nicIp[0].GetReadableIP(), errInfo.remoteRankInfo.nicIp[0].GetReadableIP(), port);
     314            2 :     CHK_RET(nicSocket_->Init());
     315            2 :     CHK_RET(nicSocket_->Listen());
     316            1 :     CHK_RET(AddWhiteList(nicSocket_, NicType::DEVICE_NIC_TYPE, tag)); // 添加白名单
     317            1 :     HCCL_INFO("[CreateDetectNicLinks]AddWhiteList finished");
     318              : 
     319            1 :     u32 acceptTimeOutAccept = 1;
     320            1 :     auto acceptTimeOut = std::chrono::seconds(GetExternalInputDfsConnectionFaultDetectionTime());
     321            1 :     std::shared_ptr<HcclSocket> acceptSuccessSocket;
     322            1 :     startTime = std::chrono::steady_clock::now();
     323              :     HcclResult ret;
     324           11 :     while (threadExit_ && (std::chrono::steady_clock::now() - startTime) <= acceptTimeOut) {
     325           10 :         ret = nicSocket_->Accept(tag, acceptSuccessSocket, acceptTimeOutAccept);
     326           10 :         if (ret == HCCL_SUCCESS) {
     327            0 :             HCCL_INFO("[CreateDetectNicLinks]accept success, localIpAddr[%s], acceptSuccessSocket[%p]",
     328              :                 errInfo.localRankInfo.nicIp[0].GetReadableIP(), acceptSuccessSocket.get());
     329            0 :             listenNicVec_.push_back(acceptSuccessSocket);
     330              :         }
     331           10 :         usleep(ACCEPT_TIME_OF_USLEEP); // 休眠100毫秒
     332              :     }
     333              :     // 循环发送
     334            1 :     startTime = std::chrono::steady_clock::now();
     335           11 :     while (threadExit_ && (std::chrono::steady_clock::now() - startTime) <= std::chrono::seconds(broadCastTime)) {
     336           10 :         std::unique_lock<std::mutex> lock(readRecvErrtInfo_);
     337           20 :         for (auto &recvError : recvErrorInfoMap_) {
     338           10 :             auto it = sendErrorInfoMap_.find(recvError.first);
     339           10 :             if (it != sendErrorInfoMap_.end() && !sendErrorInfoMap_[recvError.first].isSendNic) {
     340            2 :                 for (auto &socket : listenNicVec_) {
     341            1 :                     CHK_RET(socket->Send(&recvError.second, sizeof(recvError.second)));
     342              :                 }
     343              :             // 给所有socket都发送完成后,才标记发送完成
     344            1 :             sendErrorInfoMap_[recvError.first].isSendNic = true;
     345              :             }
     346              :         }
     347           10 :         lock.unlock();
     348           10 :         usleep(ACCEPT_TIME_OF_USLEEP); // 休眠10毫秒,将锁释放给IRecv
     349           10 :     }
     350            1 :     std::unique_lock<std::mutex> lock(whiteListMutex_);
     351            1 :     CHK_RET(DelWhiteList(errInfo.localRankInfo.nicIp[0], nicWhiteListInfosVec_, nicSocket_)); // 删除白名单
     352            1 :     lock.unlock();
     353            1 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     354            1 :         hrtResetDevice(errInfo.deviceLogicId);
     355              :     }
     356            1 :     HCCL_INFO("[CreateDetectNicLinks] completed");
     357            1 :     return HCCL_SUCCESS;
     358            2 : }
     359              : 
     360            4 : HcclResult DetectConnectionAnomalies::CreateServers(struct ErrInfo errInfo)
     361              : {
     362            4 :     if (threadExit_) {
     363            3 :         if (!isCreateLink_) {
     364            1 :             detectVnicThread_.reset(new (std::nothrow) std::thread(&DetectConnectionAnomalies::CreateDetectVnicLinks,
     365            1 :                 this, errInfo));
     366            1 :             CHK_SMART_PTR_NULL(detectVnicThread_);
     367            1 :             isCreateLink_ = true;
     368              :         }
     369              :         // 多机场景,且vnic失败时, 这里得用nicIp,否则添加白名单无效
     370            3 :         if (isNeedNic_ && !isCreateNicLink_) {
     371            1 :             detectNicThread_.reset(new (std::nothrow) std::thread(&DetectConnectionAnomalies::CreateDetectNicLinks,
     372            1 :                 this, errInfo));
     373            1 :             CHK_SMART_PTR_NULL(detectNicThread_);
     374            1 :             isCreateNicLink_ = true;
     375              :         }
     376              :     }
     377            4 :     return HCCL_SUCCESS;
     378              : }
     379              : 
     380            5 : std::string DetectConnectionAnomalies::GetTag(HcclIpAddress &Ip, int i)
     381              : {
     382           15 :     return std::string(Ip.GetReadableIP()) + "_detect_" + std::to_string(i);
     383              : }
     384              : 
     385            2 : HcclResult DetectConnectionAnomalies::AddWhiteList(
     386              :     std::shared_ptr<HcclSocket> socket,
     387              :     NicType nicType, 
     388              :     std::string& tag)
     389              : {
     390              :     // 根据 NicType 处理白名单
     391              :     HcclResult ret;
     392            2 :     if (nicType == NicType::VNIC_TYPE) {
     393            0 :         for (const auto& ipAddr : uniqueIps_) {
     394            0 :             HcclResult res = AddWlistEntry(ipAddr, tag, whiteVnicSet_, vnicWhiteListInfosVec_);
     395            0 :             if (res != HCCL_SUCCESS) {
     396            0 :                 return res;
     397              :             }
     398              :         }
     399            0 :         ret = socket->AddWhiteList(vnicWhiteListInfosVec_);
     400            0 :         if (ret != HCCL_SUCCESS) {
     401            0 :             HCCL_ERROR("[AddWhiteList] fail");
     402            0 :             return HCCL_E_NOT_FOUND;
     403              :         }
     404            2 :     } else if (isNeedNic_) {
     405            2 :         for (const auto& ipAddr : uniqueIps_) {
     406            1 :             HcclResult res = AddWlistEntry(ipAddr, tag, whiteNicSet_, nicWhiteListInfosVec_);
     407            1 :             if (res != HCCL_SUCCESS) {
     408            0 :                 return res;
     409              :             }
     410              :         }
     411            1 :         ret = socket->AddWhiteList(nicWhiteListInfosVec_);
     412            1 :         if (ret != HCCL_SUCCESS) {
     413            0 :             HCCL_ERROR("[AddWhiteList] fail");
     414            0 :             return HCCL_E_NOT_FOUND;
     415              :         }
     416              :     }
     417            2 :     return HCCL_SUCCESS;
     418              : }
     419              : 
     420            2 : HcclResult DetectConnectionAnomalies::DelWhiteList(HcclIpAddress &localIpAddr, 
     421              :     std::vector<struct SocketWlistInfo> whiteListInfos, std::shared_ptr<HcclSocket> socket)
     422              : {
     423            2 :     if (!threadExit_ || whiteListInfos.size() == 0) {
     424            2 :         return HCCL_SUCCESS;
     425              :     }
     426            0 :     HcclResult ret = socket->DelWhiteList(whiteListInfos);
     427            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[DelWhiteList]ip[%s] DelWhiteList fail", localIpAddr.GetReadableIP()),
     428              :         HCCL_E_NOT_FOUND);
     429            0 :     whiteListInfos.clear();
     430            0 :     return HCCL_SUCCESS;
     431              : }
     432              : 
     433            2 : HcclResult DetectConnectionAnomalies::ConstructErrorInfo(std::shared_ptr<HcclSocket> &clientSocket,
     434              :     RankInfo &localRankInfo, RankInfo &remoteRankInfo)
     435              : {
     436            2 :     DetectInfo  detectInfo{};
     437            2 :     detectInfo.localDeviceId = localRankInfo.devicePhyId;
     438            2 :     detectInfo.remoteDeviceId = remoteRankInfo.devicePhyId;
     439              : 
     440              :     // 获取本地设备IP并复制到错误信息中(直接获取,因为vnic场景从localRankInfo获得的IP可能是无效的)
     441            2 :     std::string localDeviceIp = clientSocket->GetLocalIp().GetReadableIP();
     442            2 :     CHK_SAFETY_FUNC_RET(memcpy_s(detectInfo.localDeviceIp, DEST_MAX_LEN, localDeviceIp.c_str(), localDeviceIp.size()));
     443            2 :     detectInfo.localDeviceIp[localDeviceIp.size()] = '\0';
     444              :     // 获取远程设备IP并复制到错误信息中
     445            2 :     std::string remoteDeviceIp = clientSocket->GetRemoteIp().GetReadableIP();
     446            2 :     CHK_SAFETY_FUNC_RET(
     447              :         memcpy_s(detectInfo.remoteDeviceIp, DEST_MAX_LEN, remoteDeviceIp.c_str(), remoteDeviceIp.size()));
     448            2 :     detectInfo.remoteDeviceIp[remoteDeviceIp.size()] = '\0';
     449              :     // 复制本地ServerId ID到错误信息中
     450            2 :     std::string localServerId = localRankInfo.serverId;
     451            2 :     CHK_SAFETY_FUNC_RET(memcpy_s(detectInfo.localServerId, DEST_MAX_LEN, localServerId.c_str(),
     452              :         localServerId.size()));
     453            2 :     detectInfo.localServerId[localServerId.size()] = '\0';
     454              : 
     455              :     // 复制远程serverId到错误信息中
     456            2 :     std::string remoteServerId = remoteRankInfo.serverId;
     457            2 :     CHK_SAFETY_FUNC_RET(memcpy_s(detectInfo.remoteServerId, DEST_MAX_LEN, remoteServerId.c_str(),
     458              :         remoteServerId.size()));
     459            2 :     detectInfo.remoteServerId[remoteServerId.size()] = '\0';
     460              : 
     461            2 :     std::unique_lock<std::mutex> lock(readRecvErrtInfo_);
     462            2 :     std::string ip = localDeviceIp + "-" + remoteDeviceIp;
     463            2 :     recvErrorInfoMap_.emplace(ip, detectInfo);
     464            2 :     sendErrorInfoMap_.emplace(ip, SendInfo{});
     465              : 
     466            2 :     lock.unlock();
     467              :     // 保存错误信息
     468            2 :     return HCCL_SUCCESS;
     469            2 : }
     470              : 
     471            3 : HcclResult DetectConnectionAnomalies::GetStatus(struct ErrInfo errInfo, std::shared_ptr<HcclSocket> &clientSocket)
     472              : {
     473            3 :     startTime = std::chrono::steady_clock::now();
     474            3 :     auto timeout = std::chrono::seconds(GetExternalInputDfsConnectionFaultDetectionTime());
     475              :     // 等待时间不大于超时时间
     476            3 :     HcclSocketStatus status = HcclSocketStatus::SOCKET_INIT;
     477              : 
     478            4 :     while ((std::chrono::steady_clock::now() - startTime) < timeout) {
     479            3 :         status = clientSocket->GetStatus();
     480            3 :         if (status == HcclSocketStatus::SOCKET_OK) {
     481            2 :             HCCL_INFO("[Detect][ConnectionAnomalies]GetStatus success, remoteIpAddr[%s]",
     482              :                 clientSocket->GetRemoteIp().GetReadableIP());
     483            2 :             return HCCL_SUCCESS;
     484              :         }
     485            1 :         SaluSleep(CLIENT_TIME_OF_USLEEP); // 休眠500毫秒
     486              :     }
     487            1 :     std::unique_lock<std::mutex> lock(ipConstuctMutex_);
     488            1 :     CHK_RET(ConstructErrorInfo(clientSocket, errInfo.localRankInfo, errInfo.remoteRankInfo));
     489            1 :     lock.unlock();
     490            1 :     return HCCL_E_TIMEOUT;
     491            1 : }
     492              : 
     493            2 : HcclResult DetectConnectionAnomalies::Connect(struct ErrInfo errInfo, std::shared_ptr<HcclSocket> &clientSocket)
     494              : {
     495            2 :    HcclIpAddress localIp = (errInfo.nicType == NicType::VNIC_TYPE) ? errInfo.localRankInfo.deviceVnicIp :
     496            2 :         errInfo.localRankInfo.nicIp[0];
     497              : 
     498            2 :     HcclNetDevCtx Ctx = (errInfo.nicType == NicType::VNIC_TYPE) ? vnicCtx_ : nicCtx_;
     499            2 :     if (Ctx == nullptr) {
     500            1 :         CHK_RET(HcclNetOpenDev(&Ctx, errInfo.nicType, errInfo.localRankInfo.devicePhyId,
     501              :             errInfo.deviceLogicId, localIp));
     502            1 :         CHK_PTR_NULL(Ctx);
     503            1 :         std::lock_guard<std::mutex> lock(clientResourcesMutex_);
     504            1 :         clientNicCtxs_.push_back(Ctx);
     505            1 :     }
     506              : 
     507            2 :     u32 port = (errInfo.nicType == NicType::VNIC_TYPE) ? errInfo.remoteRankInfo.deviceVnicPort : errInfo.remoteRankInfo.deviceNicPort;
     508            2 :     port = (port == HCCL_INVALID_PORT) ? HETEROG_CCL_PORT : port;
     509            2 :     HcclIpAddress remoteIpAddr = (errInfo.nicType == NicType::VNIC_TYPE) ? errInfo.remoteRankInfo.deviceVnicIp : errInfo.remoteRankInfo.nicIp[0];
     510              : 
     511            2 :     std::string tag = GetTag(remoteIpAddr);
     512            2 :     HCCL_INFO("[Connect]tag[%s], port[%u], nicCtx[%p], remoteIpAddr[%s], role[%d]", tag.c_str(),
     513              :         port, Ctx, remoteIpAddr.GetReadableIP(), HcclSocketRole::SOCKET_ROLE_CLIENT);
     514            2 :     EXCEPTION_CATCH((clientSocket = std::make_shared<HcclSocket>(tag, Ctx, remoteIpAddr, port, HcclSocketRole::SOCKET_ROLE_CLIENT)),
     515              :     return HCCL_E_PTR);
     516            2 :     CHK_RET(clientSocket->Init());
     517              : 
     518            2 :     HcclResult ret = clientSocket->Connect();
     519            2 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Detect][ConnectionAnomalies] connect fail, localIp[%s], remoteIp[%s]",
     520              :         localIp.GetReadableIP(), remoteIpAddr.GetReadableIP()), HCCL_E_INTERNAL);
     521            2 :     return HCCL_SUCCESS;
     522            2 : }
     523              : 
     524            2 : HcclResult DetectConnectionAnomalies::CreateClient(struct ErrInfo errInfo)
     525              : {
     526            2 :     SetThreadName("Hccl_Detect_Client");
     527            2 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     528            1 :         hrtSetDevice(errInfo.deviceLogicId);
     529              :     }
     530            2 :     std::shared_ptr<HcclSocket> clientSocket;
     531            2 :     CHK_RET(Connect(errInfo, clientSocket));
     532            2 :     HcclResult ret = GetStatus(errInfo, clientSocket);
     533            2 :     if (ret != HCCL_SUCCESS) {
     534            1 :         HCCL_ERROR("[CreateClientConnect]GetStatus fail, ret[%d]", ret);
     535            1 :         return ret;
     536              :     }
     537              :     // 将localServerId转换char,以便打印函数统一
     538            1 :     char localServerId[DEST_MAX_LEN]{};
     539            1 :     CHK_SAFETY_FUNC_RET(memcpy_s(localServerId, DEST_MAX_LEN, errInfo.localRankInfo.serverId.c_str(),
     540              :         errInfo.localRankInfo.serverId.size()));
     541            1 :     localServerId[errInfo.localRankInfo.serverId.size()] = '\0';
     542              : 
     543              :     // 保存clientSocket,在析构时join
     544            1 :     clientResourcesMutex_.lock();
     545            1 :     clientSockets_.push_back(clientSocket);
     546            1 :     clientResourcesMutex_.unlock();
     547              : 
     548              :     // 开始计时
     549            1 :     auto waitTime = std::chrono::seconds(GetExternalInputDfsConnectionFaultDetectionTime()) +
     550            2 :         std::chrono::seconds(broadCastTime);
     551            1 :     startTime = std::chrono::steady_clock::now();
     552              : 
     553            1 :     DetectInfo detectInfo{};
     554            1 :     u64 totalSize = sizeof(detectInfo);
     555            1 :     void *recvBuffer = reinterpret_cast<void *>(&detectInfo);
     556            1 :     u64 recvSize = 0;
     557            1 :     while (threadExit_ && (std::chrono::steady_clock::now() - startTime) < waitTime) {
     558            0 :         u64 compSize = 0; // 本次接收长度
     559            0 :         void *recvBufferTmp = reinterpret_cast<u8 *>(recvBuffer) + recvSize; // 偏移
     560            0 :         ret = clientSocket->IRecv(recvBufferTmp, totalSize - recvSize, compSize);
     561            0 :         if (ret == HCCL_SUCCESS && compSize > 0) {
     562            0 :             recvSize += compSize;
     563              :         }
     564            0 :         if ((totalSize - recvSize) == 0) {
     565            0 :             recvSize = 0;
     566            0 :             std::string loaclIp(detectInfo.localDeviceIp);
     567            0 :             std::string remoteIp(detectInfo.remoteDeviceIp);
     568            0 :             std::string ip = loaclIp + "-" + remoteIp;
     569            0 :             std::unique_lock<std::mutex> lock(readRecvErrtInfo_);
     570            0 :             auto it  = recvErrorInfoMap_.find(ip);
     571            0 :             if (it == recvErrorInfoMap_.end()) {
     572            0 :                 recvErrorInfoMap_.emplace(ip, detectInfo);
     573            0 :                 sendErrorInfoMap_.emplace(ip, SendInfo{});
     574              :             }
     575            0 :             CHK_SAFETY_FUNC_RET(memset_s(&detectInfo, sizeof(DetectInfo), 0, sizeof(DetectInfo)));
     576            0 :             lock.unlock();
     577            0 :         }
     578            0 :         usleep(IRECV_TIME_OF_USLEEP); // 休眠500毫秒
     579              :     }
     580            1 :     if (errInfo.deviceLogicId != HOST_DEVICE_ID) {
     581            0 :         hrtResetDevice(errInfo.deviceLogicId);
     582              :     }
     583            1 :     HCCL_INFO("[CreateClient]completed");
     584            1 :     return HCCL_SUCCESS;
     585            2 : }
     586              : 
     587            1 : HcclResult DetectConnectionAnomalies::CreateClients(struct ErrInfo errInfo, std::vector<std::unique_ptr<std::thread>> &linkClientThreads)
     588              : {
     589            1 :     std::unique_ptr<std::thread> linkClientThread;
     590            1 :     linkClientThread.reset(new (std::nothrow) std::thread(&DetectConnectionAnomalies::CreateClient, this, errInfo));
     591            1 :     CHK_SMART_PTR_NULL(linkClientThread);
     592            1 :     linkClientThreads.emplace_back(std::move(linkClientThread));
     593            1 :     return HCCL_SUCCESS;
     594            1 : }
     595              : 
     596            0 : std::string DetectConnectionAnomalies::FormatDetectMessage(const std::string &localServerId, s32 localDeviceId, const DetectInfo &detectInfo)
     597              : {
     598            0 :     return std::string("This node (server ") + 
     599            0 :         localServerId  + ", device ID " + std::to_string(localDeviceId) +
     600            0 :         ") detects that srcRank (server " + detectInfo.localServerId +
     601            0 :         ", device ID " + std::to_string(detectInfo.localDeviceId) +
     602            0 :         ") fails to connect to dstRank (server " + detectInfo.remoteServerId +
     603            0 :         ", device ID " + std::to_string(detectInfo.remoteDeviceId) +
     604            0 :         "). Continue to analyze the fault based on the logs of srcRank and dstRank.";
     605              : }
     606              : 
     607          808 : void DetectConnectionAnomalies::ThreadDestroy()
     608              : {
     609          808 :     HCCL_DEBUG("[DetectConnectionAnomalies]Destroy");
     610          808 :     threadExit_ = false;
     611              : 
     612              :     // 销毁client线程
     613          808 :     std::unique_lock<std::mutex> lock(clientThreadMutex_);
     614          808 :     for (u32 index = 0; index < linkClientThreads_.size(); index++) {
     615            0 :         if (linkClientThreads_[index] != nullptr && linkClientThreads_[index]->joinable()) {
     616            0 :             HCCL_INFO("[DetectConnectionAnomalies]Destroy linkClientThreads_[%p]", linkClientThreads_[index].get());
     617            0 :             linkClientThreads_[index]->join(); // 等待线程执行完毕
     618            0 :             linkClientThreads_[index] = nullptr;
     619              :         }
     620              :     }
     621          808 :     linkClientThreads_.clear();
     622          808 :     lock.unlock();
     623              : 
     624              :     // 先销毁线程,再释放资源
     625              :     // 销毁server线程
     626          808 :     if (detectVnicThread_ != nullptr && detectVnicThread_->joinable()) {
     627            0 :         detectVnicThread_->join();
     628            0 :         detectVnicThread_ = nullptr;
     629              :     }
     630              : 
     631          808 :     if (detectNicThread_ != nullptr && detectNicThread_->joinable()) {
     632            0 :         detectNicThread_->join();
     633            0 :         detectNicThread_ = nullptr;
     634              :     }
     635              : 
     636              :     // 销毁轮询线程
     637          808 :     if(getIpNictypeQueue_ != nullptr && getIpNictypeQueue_->joinable()) {
     638            0 :         getIpNictypeQueue_->join();
     639            0 :         getIpNictypeQueue_ = nullptr;
     640              :     }
     641              : 
     642              :     // 释放server侧资源
     643          808 :     if (vnicSocket_ != nullptr) {
     644            0 :         for (auto &socket : listenVnicVec_) {
     645            0 :             socket->DeInit();
     646            0 :             socket = nullptr;
     647              :         }
     648            0 :         vnicSocket_->DeInit();
     649            0 :         vnicSocket_ = nullptr;
     650              :     }
     651              : 
     652          808 :     if (nicSocket_ != nullptr) {
     653            3 :         for (auto &socket : listenNicVec_) {
     654            1 :             socket->DeInit();
     655              :         }
     656            2 :         nicSocket_->DeInit();
     657            2 :         nicSocket_ = nullptr;
     658              :     }
     659              : 
     660              :     // 释放client资源
     661          808 :     for (auto &socket : clientSockets_) {
     662            0 :         if (socket != nullptr) {
     663            0 :             socket->DeInit();
     664            0 :             socket = nullptr;
     665              :         }
     666              :     }
     667              : 
     668              :     // 销毁ctx
     669          808 :     if (nicCtx_ != nullptr) {
     670            2 :         HcclNetCloseDev(nicCtx_);
     671            2 :         nicCtx_ = nullptr;
     672              :     }
     673              : 
     674          808 :     if (vnicCtx_ != nullptr) {
     675            0 :         HcclNetCloseDev(vnicCtx_);
     676            0 :         vnicCtx_ = nullptr;
     677              :     }
     678              : 
     679          809 :     for (auto nicCtx : clientNicCtxs_) {
     680            1 :         if (nicCtx != nullptr) {
     681            1 :             HcclNetCloseDev(nicCtx);
     682              :         }
     683              :     }
     684          808 :     clientNicCtxs_.clear();
     685          808 :     clientSockets_.clear();
     686          808 :     listenVnicVec_.clear();
     687          808 :     listenNicVec_.clear();
     688          808 : }
     689          808 : void DetectConnectionAnomalies::Deinit()
     690              : {
     691          808 :     int count = initRef_.Unref();
     692          808 :     if (count > 0) {
     693            0 :         HCCL_INFO("[DetectConnectionAnomalies]Deinit initRef_[%d]", count);
     694            0 :         return;
     695          808 :     } else if (count < 0) {
     696          756 :         HCCL_WARNING("[DetectConnectionAnomalies]Deinit failed");
     697              :     }
     698          808 :     ThreadDestroy();
     699          808 :     HCCL_INFO("DetectConnectionAnomalies[Deinit] count[%d]", count);
     700          808 :     return;
     701              : }
     702              : 
     703            0 : void AddIpQueue(RankInfo &localRankInfo, RankInfo &remoteRankInfo, NicType nicType,
     704              :     s32 deviceLogicId)
     705              : {
     706            0 :     DetectConnectionAnomalies::GetInstance(deviceLogicId).AddIpQueue(localRankInfo, remoteRankInfo,
     707              :         nicType, deviceLogicId);
     708            0 :     return;
     709              : }
     710              : 
     711           43 : __attribute__((constructor)) void DetetcCallBackAddIpQueue()
     712              : {
     713           43 :     DetectCallBack(AddIpQueue);
     714           43 : }
     715              : } // namespace hccl
        

Generated by: LCOV version 2.0-1