2929
3030# from net_address.h
3131NETWORK_TYPE_UNROUTABLE = 0
32+ # Use in -maxconnections. Results in a maximum of 21 inbound connections
33+ MAX_CONNECTIONS = 32
34+ MAX_INBOUND_CONNECTIONS = MAX_CONNECTIONS - 10 - 1 # 10 outbound and 1 feeler
3235
3336net_tracepoints_program = """
3437#include <uapi/linux/ptrace.h>
7073 u64 existing;
7174};
7275
76+ struct ClosedConnection
77+ {
78+ struct Connection conn;
79+ u64 time_established;
80+ };
81+
7382BPF_PERF_OUTPUT(inbound_messages);
7483int trace_inbound_message(struct pt_regs *ctx) {
7584 struct p2p_message msg = {};
126135 return 0;
127136};
128137
138+ BPF_PERF_OUTPUT(evicted_inbound_connections);
139+ int trace_evicted_inbound_connection(struct pt_regs *ctx) {
140+ void *conn_type_pointer = NULL, *address_pointer = NULL;
141+ void* address_pointer;
142+ bpf_usdt_readarg(1, ctx, &evicted.conn.id);
143+ bpf_usdt_readarg(2, ctx, &address_pointer);
144+ bpf_usdt_readarg(3, ctx, &conn_type_pointer);
145+ bpf_usdt_readarg(4, ctx, &evicted.conn.network);
146+ bpf_usdt_readarg(5, ctx, &evicted.time_established);
147+ bpf_probe_read_user_str(&evicted.conn.addr, sizeof(evicted.conn.addr), address_pointer);
148+ bpf_probe_read_user_str(&evicted.conn.type, sizeof(evicted.conn.type), conn_type_pointer);
149+ evicted_inbound_connections.perf_submit(ctx, &evicted, sizeof(evicted));
150+ return 0;
151+ };
152+
129153"""
130154
131155
@@ -150,9 +174,19 @@ class NewConnection(ctypes.Structure):
150174 def __repr__ (self ):
151175 return f"NewConnection(conn={ self .conn } , existing={ self .existing } )"
152176
177+ class ClosedConnection (ctypes .Structure ):
178+ _fields_ = [
179+ ("conn" , Connection ),
180+ ("time_established" , ctypes .c_uint64 ),
181+ ]
182+
183+ def __repr__ (self ):
184+ return f"ClosedConnection(conn={ self .conn } , time_established={ self .time_established } )"
185+
153186class NetTracepointTest (BitcoinTestFramework ):
154187 def set_test_params (self ):
155188 self .num_nodes = 1
189+ self .extra_args = [[f'-maxconnections={ MAX_CONNECTIONS } ' ]]
156190
157191 def skip_test_if_missing_module (self ):
158192 self .skip_if_platform_not_linux ()
@@ -164,6 +198,7 @@ def run_test(self):
164198 self .p2p_message_tracepoint_test ()
165199 self .inbound_conn_tracepoint_test ()
166200 self .outbound_conn_tracepoint_test ()
201+ self .evicted_inbound_conn_tracepoint_test ()
167202
168203 def p2p_message_tracepoint_test (self ):
169204 # Tests the net:inbound_message and net:outbound_message tracepoints
@@ -320,5 +355,42 @@ def handle_outbound_connection(_, data, __):
320355 for node in testnodes :
321356 node .peer_disconnect ()
322357
358+ def evicted_inbound_conn_tracepoint_test (self ):
359+ self .log .info ("hook into the net:evicted_inbound_connection tracepoint" )
360+ ctx = USDT (pid = self .nodes [0 ].process .pid )
361+ ctx .enable_probe (probe = "net:evicted_inbound_connection" ,
362+ fn_name = "trace_evicted_inbound_connection" )
363+ bpf = BPF (text = net_tracepoints_program , usdt_contexts = [ctx ], debug = 0 , cflags = ["-Wno-error=implicit-function-declaration" ])
364+
365+ EXPECTED_EVICTED_CONNECTIONS = 2
366+ evicted_connections = []
367+
368+ def handle_evicted_inbound_connection (_ , data , __ ):
369+ event = ctypes .cast (data , ctypes .POINTER (ClosedConnection )).contents
370+ self .log .info (f"handle_evicted_inbound_connection(): { event } " )
371+ evicted_connections .append (event )
372+
373+ bpf ["evicted_inbound_connections" ].open_perf_buffer (handle_evicted_inbound_connection )
374+
375+ self .log .info (
376+ f"connect { MAX_INBOUND_CONNECTIONS + EXPECTED_EVICTED_CONNECTIONS } P2P test nodes to our bitcoind node and expect { EXPECTED_EVICTED_CONNECTIONS } evictions" )
377+ testnodes = list ()
378+ for p2p_idx in range (MAX_INBOUND_CONNECTIONS + EXPECTED_EVICTED_CONNECTIONS ):
379+ testnode = P2PInterface ()
380+ self .nodes [0 ].add_p2p_connection (testnode )
381+ testnodes .append (testnode )
382+ bpf .perf_buffer_poll (timeout = 200 )
383+
384+ assert_equal (EXPECTED_EVICTED_CONNECTIONS , len (evicted_connections ))
385+ for evicted_connection in evicted_connections :
386+ assert evicted_connection .conn .id > 0
387+ assert evicted_connection .time_established > 0
388+ assert_equal ("inbound" , evicted_connection .conn .conn_type .decode ('utf-8' ))
389+ assert_equal (NETWORK_TYPE_UNROUTABLE , evicted_connection .conn .network )
390+
391+ bpf .cleanup ()
392+ for node in testnodes :
393+ node .peer_disconnect ()
394+
323395if __name__ == '__main__' :
324396 NetTracepointTest (__file__ ).main ()
0 commit comments