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