Skip to content

Commit 3ea54e5

Browse files
committed
net: Add continuous ASMap health check logging
1 parent 28d7e55 commit 3ea54e5

File tree

5 files changed

+62
-0
lines changed

5 files changed

+62
-0
lines changed

src/net.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3305,6 +3305,12 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
33053305
// Dump network addresses
33063306
scheduler.scheduleEvery([this] { DumpAddresses(); }, DUMP_PEERS_INTERVAL);
33073307

3308+
// Run the ASMap Health check once and then schedule it to run every 24h.
3309+
if (m_netgroupman.UsingASMap()) {
3310+
ASMapHealthCheck();
3311+
scheduler.scheduleEvery([this] { ASMapHealthCheck(); }, ASMAP_HEALTH_CHECK_INTERVAL);
3312+
}
3313+
33083314
return true;
33093315
}
33103316

@@ -3853,6 +3859,19 @@ void CConnman::PerformReconnections()
38533859
}
38543860
}
38553861

3862+
void CConnman::ASMapHealthCheck()
3863+
{
3864+
const std::vector<CAddress> v4_addrs{GetAddresses(/*max_addresses=*/ 0, /*max_pct=*/ 0, Network::NET_IPV4, /*filtered=*/ false)};
3865+
const std::vector<CAddress> v6_addrs{GetAddresses(/*max_addresses=*/ 0, /*max_pct=*/ 0, Network::NET_IPV6, /*filtered=*/ false)};
3866+
std::vector<CNetAddr> clearnet_addrs;
3867+
clearnet_addrs.reserve(v4_addrs.size() + v6_addrs.size());
3868+
std::transform(v4_addrs.begin(), v4_addrs.end(), std::back_inserter(clearnet_addrs),
3869+
[](const CAddress& addr) { return static_cast<CNetAddr>(addr); });
3870+
std::transform(v6_addrs.begin(), v6_addrs.end(), std::back_inserter(clearnet_addrs),
3871+
[](const CAddress& addr) { return static_cast<CNetAddr>(addr); });
3872+
m_netgroupman.ASMapHealthCheck(clearnet_addrs);
3873+
}
3874+
38563875
// Dump binary message to file, with timestamp.
38573876
static void CaptureMessageToFile(const CAddress& addr,
38583877
const std::string& msg_type,

src/net.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ static const bool DEFAULT_BLOCKSONLY = false;
8787
static const int64_t DEFAULT_PEER_CONNECT_TIMEOUT = 60;
8888
/** Number of file descriptors required for message capture **/
8989
static const int NUM_FDS_MESSAGE_CAPTURE = 1;
90+
/** Interval for ASMap Health Check **/
91+
static constexpr std::chrono::hours ASMAP_HEALTH_CHECK_INTERVAL{24};
9092

9193
static constexpr bool DEFAULT_FORCEDNSSEED{false};
9294
static constexpr bool DEFAULT_DNSSEED{true};
@@ -1138,6 +1140,7 @@ class CConnman
11381140
void SetNetworkActive(bool active);
11391141
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant&& grant_outbound, const char* strDest, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
11401142
bool CheckIncomingNonce(uint64_t nonce);
1143+
void ASMapHealthCheck();
11411144

11421145
// alias for thread safety annotations only, not defined
11431146
RecursiveMutex& GetNodesMutex() const LOCK_RETURNED(m_nodes_mutex);

src/netgroup.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <netgroup.h>
66

77
#include <hash.h>
8+
#include <logging.h>
89
#include <util/asmap.h>
910

1011
uint256 NetGroupManager::GetAsmapChecksum() const
@@ -109,3 +110,23 @@ uint32_t NetGroupManager::GetMappedAS(const CNetAddr& address) const
109110
uint32_t mapped_as = Interpret(m_asmap, ip_bits);
110111
return mapped_as;
111112
}
113+
114+
void NetGroupManager::ASMapHealthCheck(const std::vector<CNetAddr>& clearnet_addrs) const {
115+
std::set<uint32_t> clearnet_asns{};
116+
int unmapped_count{0};
117+
118+
for (const auto& addr : clearnet_addrs) {
119+
uint32_t asn = GetMappedAS(addr);
120+
if (asn == 0) {
121+
++unmapped_count;
122+
continue;
123+
}
124+
clearnet_asns.insert(asn);
125+
}
126+
127+
LogPrintf("ASMap Health Check: %i clearnet peers are mapped to %i ASNs with %i peers being unmapped\n", clearnet_addrs.size(), clearnet_asns.size(), unmapped_count);
128+
}
129+
130+
bool NetGroupManager::UsingASMap() const {
131+
return m_asmap.size() > 0;
132+
}

src/netgroup.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ class NetGroupManager {
4141
*/
4242
uint32_t GetMappedAS(const CNetAddr& address) const;
4343

44+
/**
45+
* Analyze and log current health of ASMap based buckets.
46+
*/
47+
void ASMapHealthCheck(const std::vector<CNetAddr>& clearnet_addrs) const;
48+
49+
/**
50+
* Indicates whether ASMap is being used for clearnet bucketing.
51+
*/
52+
bool UsingASMap() const;
53+
4454
private:
4555
/** Compressed IP->ASN mapping, loaded from a file when a node starts.
4656
*

test/functional/feature_asmap.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ def test_empty_asmap(self):
111111
self.node.assert_start_raises_init_error(extra_args=['-asmap'], expected_msg=msg)
112112
os.remove(self.default_asmap)
113113

114+
def test_asmap_health_check(self):
115+
self.log.info('Test bitcoind -asmap logs ASMap Health Check with basic stats')
116+
shutil.copyfile(self.asmap_raw, self.default_asmap)
117+
msg = "ASMap Health Check: 2 clearnet peers are mapped to 1 ASNs with 0 peers being unmapped"
118+
with self.node.assert_debug_log(expected_msgs=[msg]):
119+
self.start_node(0, extra_args=['-asmap'])
120+
os.remove(self.default_asmap)
121+
114122
def run_test(self):
115123
self.node = self.nodes[0]
116124
self.datadir = self.node.chain_path
@@ -124,6 +132,7 @@ def run_test(self):
124132
self.test_asmap_interaction_with_addrman_containing_entries()
125133
self.test_default_asmap_with_missing_file()
126134
self.test_empty_asmap()
135+
self.test_asmap_health_check()
127136

128137

129138
if __name__ == '__main__':

0 commit comments

Comments
 (0)