29
29
30
30
# from net_address.h
31
31
NETWORK_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
32
35
33
36
net_tracepoints_program = """
34
37
#include <uapi/linux/ptrace.h>
70
73
u64 existing;
71
74
};
72
75
76
+ struct ClosedConnection
77
+ {
78
+ struct Connection conn;
79
+ u64 time_established;
80
+ };
81
+
73
82
BPF_PERF_OUTPUT(inbound_messages);
74
83
int trace_inbound_message(struct pt_regs *ctx) {
75
84
struct p2p_message msg = {};
126
135
return 0;
127
136
};
128
137
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
+
129
153
"""
130
154
131
155
@@ -150,9 +174,19 @@ class NewConnection(ctypes.Structure):
150
174
def __repr__ (self ):
151
175
return f"NewConnection(conn={ self .conn } , existing={ self .existing } )"
152
176
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
+
153
186
class NetTracepointTest (BitcoinTestFramework ):
154
187
def set_test_params (self ):
155
188
self .num_nodes = 1
189
+ self .extra_args = [[f'-maxconnections={ MAX_CONNECTIONS } ' ]]
156
190
157
191
def skip_test_if_missing_module (self ):
158
192
self .skip_if_platform_not_linux ()
@@ -164,6 +198,7 @@ def run_test(self):
164
198
self .p2p_message_tracepoint_test ()
165
199
self .inbound_conn_tracepoint_test ()
166
200
self .outbound_conn_tracepoint_test ()
201
+ self .evicted_inbound_conn_tracepoint_test ()
167
202
168
203
def p2p_message_tracepoint_test (self ):
169
204
# Tests the net:inbound_message and net:outbound_message tracepoints
@@ -320,5 +355,42 @@ def handle_outbound_connection(_, data, __):
320
355
for node in testnodes :
321
356
node .peer_disconnect ()
322
357
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
+
323
395
if __name__ == '__main__' :
324
396
NetTracepointTest (__file__ ).main ()
0 commit comments