146
146
147
147
BPF_PERF_OUTPUT(evicted_inbound_connections);
148
148
int trace_evicted_inbound_connection(struct pt_regs *ctx) {
149
+ struct ClosedConnection evicted = {};
149
150
void *conn_type_pointer = NULL, *address_pointer = NULL;
150
- void* address_pointer;
151
151
bpf_usdt_readarg(1, ctx, &evicted.conn.id);
152
152
bpf_usdt_readarg(2, ctx, &address_pointer);
153
153
bpf_usdt_readarg(3, ctx, &conn_type_pointer);
169
169
misbehaving_connections.perf_submit(ctx, &misbehaving, sizeof(misbehaving));
170
170
return 0;
171
171
};
172
+
173
+ BPF_PERF_OUTPUT(closed_connections);
174
+ int trace_closed_connection(struct pt_regs *ctx) {
175
+ struct ClosedConnection closed = {};
176
+ void *conn_type_pointer = NULL, *address_pointer = NULL;
177
+ bpf_usdt_readarg(1, ctx, &closed.conn.id);
178
+ bpf_usdt_readarg(2, ctx, &address_pointer);
179
+ bpf_usdt_readarg(3, ctx, &conn_type_pointer);
180
+ bpf_usdt_readarg(4, ctx, &closed.conn.network);
181
+ bpf_usdt_readarg(5, ctx, &closed.time_established);
182
+ bpf_probe_read_user_str(&closed.conn.addr, sizeof(closed.conn.addr), address_pointer);
183
+ bpf_probe_read_user_str(&closed.conn.type, sizeof(closed.conn.type), conn_type_pointer);
184
+ closed_connections.perf_submit(ctx, &closed, sizeof(closed));
185
+ return 0;
186
+ };
172
187
"""
173
188
174
189
@@ -193,6 +208,7 @@ class NewConnection(ctypes.Structure):
193
208
def __repr__ (self ):
194
209
return f"NewConnection(conn={ self .conn } , existing={ self .existing } )"
195
210
211
+
196
212
class ClosedConnection (ctypes .Structure ):
197
213
_fields_ = [
198
214
("conn" , Connection ),
@@ -230,6 +246,7 @@ def run_test(self):
230
246
self .outbound_conn_tracepoint_test ()
231
247
self .evicted_inbound_conn_tracepoint_test ()
232
248
self .misbehaving_conn_tracepoint_test ()
249
+ self .closed_conn_tracepoint_test ()
233
250
234
251
def p2p_message_tracepoint_test (self ):
235
252
# Tests the net:inbound_message and net:outbound_message tracepoints
@@ -457,5 +474,43 @@ def handle_misbehaving_connection(_, data, __):
457
474
458
475
bpf .cleanup ()
459
476
477
+ def closed_conn_tracepoint_test (self ):
478
+ self .log .info ("hook into the net:closed_connection tracepoint" )
479
+ ctx = USDT (pid = self .nodes [0 ].process .pid )
480
+ ctx .enable_probe (probe = "net:closed_connection" ,
481
+ fn_name = "trace_closed_connection" )
482
+ bpf = BPF (text = net_tracepoints_program , usdt_contexts = [ctx ], debug = 0 , cflags = ["-Wno-error=implicit-function-declaration" ])
483
+
484
+ EXPECTED_CLOSED_CONNECTIONS = 2
485
+ closed_connections = []
486
+
487
+ def handle_closed_connection (_ , data , __ ):
488
+ event = ctypes .cast (data , ctypes .POINTER (ClosedConnection )).contents
489
+ self .log .info (f"handle_closed_connection(): { event } " )
490
+ closed_connections .append (event )
491
+
492
+ bpf ["closed_connections" ].open_perf_buffer (handle_closed_connection )
493
+
494
+ self .log .info (
495
+ f"connect { EXPECTED_CLOSED_CONNECTIONS } P2P test nodes to our bitcoind node" )
496
+ testnodes = list ()
497
+ for p2p_idx in range (EXPECTED_CLOSED_CONNECTIONS ):
498
+ testnode = P2PInterface ()
499
+ self .nodes [0 ].add_p2p_connection (testnode )
500
+ testnodes .append (testnode )
501
+ for node in testnodes :
502
+ node .peer_disconnect ()
503
+ self .wait_until (lambda : len (self .nodes [0 ].getpeerinfo ()) == 0 )
504
+ bpf .perf_buffer_poll (timeout = 400 )
505
+
506
+ assert_equal (EXPECTED_CLOSED_CONNECTIONS , len (closed_connections ))
507
+ for closed_connection in closed_connections :
508
+ assert closed_connection .conn .id > 0
509
+ assert_equal ("inbound" , closed_connection .conn .conn_type .decode ('utf-8' ))
510
+ assert_equal (0 , closed_connection .conn .network )
511
+ assert closed_connection .time_established > 0
512
+
513
+ bpf .cleanup ()
514
+
460
515
if __name__ == '__main__' :
461
516
NetTracepointTest (__file__ ).main ()
0 commit comments