Line data Source code
1 : #include "fddev.h"
2 : #include "../../util/net/fd_pcap.h"
3 : #include <stdio.h>
4 :
5 : void
6 : dump_cmd_args( int * argc,
7 : char * * * argv,
8 0 : args_t * args ) {
9 0 : char const * out_file = fd_env_strip_cmdline_cstr( argc, argv, "--out-file", NULL, "dump.pcap" );
10 0 : char const * link = fd_env_strip_cmdline_cstr( argc, argv, "--link", NULL, "" );
11 0 : fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( args->dump.pcap_path ), out_file, sizeof(args->dump.pcap_path)-1UL ) );
12 0 : fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( args->dump.link_name ), link, sizeof(args->dump.link_name)-1UL ) );
13 0 : }
14 :
15 : static void
16 : dump_link( void * out_file,
17 : fd_topo_link_t * link,
18 0 : void * mem ) {
19 0 : fd_frag_meta_t const * mcache = link->mcache;
20 0 : ulong seq0 = fd_mcache_seq0( mcache );
21 0 : ulong seq_init = fd_mcache_seq_query( fd_mcache_seq_laddr_const( mcache ) );
22 0 : ulong depth = fd_mcache_depth( mcache );
23 :
24 0 : ulong dumped_count = 0UL;
25 :
26 0 : uint link_hash = (uint)((fd_hash( 17UL, link->name, strlen( link->name ) ) << 8) | link->kind_id);
27 : /* For links that are published reliably, we can trust the value of
28 : seq_init. For unreliable links, we'll just publish one whole
29 : depth. */
30 :
31 : /* We know at this point [seq0, seq_init) were published, but they may
32 : be long overwritten, and there may be more published than that. */
33 :
34 0 : ulong min_seq_seen = seq_init; /* What we actually dumped is [min_seq_seen, seq_init) */
35 0 : for( ulong seq=fd_seq_dec( seq_init, 1UL ); fd_seq_ge( seq, seq0 ); seq=fd_seq_dec( seq, 1UL ) ) {
36 : /* It's not necessary for this to be atomic, since this is a
37 : post-mortem tool. */
38 0 : fd_frag_meta_t const * line = mcache+fd_mcache_line_idx( seq, depth );
39 0 : ulong read_seq = fd_frag_meta_seq_query( line );
40 0 : if( FD_UNLIKELY( read_seq!=seq ) ) break;
41 :
42 0 : min_seq_seen = seq;
43 :
44 0 : ulong chunk = line->chunk;
45 0 : ulong sz = line->sz;
46 :
47 0 : void const * buffer = fd_chunk_to_laddr_const( mem, chunk );
48 :
49 0 : fd_pcap_fwrite_pkt( (long)seq, line, sizeof(fd_frag_meta_t), buffer, sz, link_hash, out_file );
50 0 : dumped_count++;
51 0 : }
52 :
53 : /* Now check everything after seq_init. This could potentially loop
54 : forever if the producer is still going, so we cap it at one depth. */
55 0 : for( ulong off=0UL; off<depth; off++ ) {
56 0 : ulong seq = fd_seq_inc( seq_init, off );
57 :
58 0 : fd_frag_meta_t const * line = mcache+fd_mcache_line_idx( seq, depth );
59 0 : ulong read_seq = fd_frag_meta_seq_query( line );
60 :
61 : /* Skip anything we processed in the first loop, also skipping any
62 : with the err control bit set. When an mcache is initialized, all
63 : the frags have err set to true, so this will skip those in
64 : particular as well. */
65 0 : if( FD_UNLIKELY( (fd_seq_le( min_seq_seen, read_seq ) & fd_seq_lt( read_seq, seq_init )) | (line->ctl & (1<<2)) ) ) continue;
66 :
67 0 : ulong chunk = line->chunk;
68 0 : ulong sz = line->sz;
69 :
70 0 : void const * buffer = fd_chunk_to_laddr_const( mem, chunk );
71 :
72 0 : fd_pcap_fwrite_pkt( (long)seq, line, sizeof(fd_frag_meta_t), buffer, sz, link_hash, out_file );
73 0 : dumped_count++;
74 0 : }
75 0 : FD_LOG_NOTICE(( "Dumped %lu frags from %s %lu. Link hash: 0x%x", dumped_count, link->name, link->kind_id, link_hash ));
76 0 : }
77 :
78 : void
79 : dump_cmd_fn( args_t * args,
80 0 : config_t * const config ) {
81 :
82 0 : FILE * out = fopen( args->dump.pcap_path, "w" );
83 0 : FD_TEST( fd_pcap_fwrite_hdr( out, FD_PCAP_LINK_LAYER_USER0 ) );
84 :
85 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY );
86 0 : fd_topo_fill( &config->topo );
87 :
88 0 : char * tokens[ 16 ];
89 0 : ulong token_count = fd_cstr_tokenize( tokens, 16UL, args->dump.link_name, ',' );
90 :
91 0 : for( ulong i=0UL; i<config->topo.link_cnt; i++ ) {
92 0 : int found = (token_count==0UL);
93 0 : for( ulong k=0UL; k<token_count; k++ ) found |= !strcmp( tokens[ k ], config->topo.links[ i ].name );
94 0 : if( found ) {
95 :
96 0 : fd_topo_link_t * link = &(config->topo.links[ i ]);
97 0 : if( (link->mcache==NULL) | (link->dcache==NULL) ) {
98 0 : FD_LOG_NOTICE(( "Skipping %s %lu", link->name, link->kind_id ));
99 0 : continue;
100 0 : }
101 0 : void * mem = config->topo.workspaces[ config->topo.objs[ link->dcache_obj_id ].wksp_id ].wksp;
102 :
103 0 : dump_link( out, link, mem );
104 0 : }
105 0 : }
106 :
107 0 : fclose( out );
108 0 : fd_topo_leave_workspaces( &config->topo );
109 0 : }
|