Line data Source code
1 : /* fd_udpecho_tile mirrors incoming UDP packets back to the source.
2 : Useful for testing connectivity issues, but somewhat dangerous to run
3 : in prod on the Internet. */
4 :
5 : #include "../../../../disco/topo/fd_topo.h"
6 :
7 : struct fd_udpecho_tile_ctx {
8 : void * in_base;
9 : void * out_base;
10 : ulong chunk0;
11 : ulong wmark;
12 : ulong chunk;
13 : ulong pkt_sz;
14 : uint ip4_dst;
15 : };
16 :
17 : typedef struct fd_udpecho_tile_ctx fd_udpecho_tile_ctx_t;
18 :
19 : FD_FN_CONST static inline ulong
20 0 : scratch_align( void ) {
21 0 : return alignof(fd_udpecho_tile_ctx_t);
22 0 : }
23 :
24 : FD_FN_PURE static inline ulong
25 0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
26 0 : return sizeof(fd_udpecho_tile_ctx_t);
27 0 : }
28 :
29 : static void
30 : unprivileged_init( fd_topo_t * topo,
31 0 : fd_topo_tile_t * tile ) {
32 0 : fd_udpecho_tile_ctx_t * ctx = fd_topo_obj_laddr( topo, tile->tile_obj_id );
33 :
34 0 : FD_TEST( tile->out_cnt==1UL );
35 0 : void * out_base = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
36 0 : void * out_dcache = topo->links[ tile->out_link_id[ 0 ] ].dcache;
37 0 : ctx->out_base = out_base;
38 0 : ctx->chunk0 = fd_dcache_compact_chunk0( out_base, out_dcache );
39 0 : ctx->wmark = fd_dcache_compact_wmark( out_base, out_dcache, FD_NET_MTU );
40 0 : ctx->chunk = ctx->chunk0;
41 :
42 0 : FD_TEST( tile->in_cnt==1UL );
43 0 : void * in_base = topo->workspaces[ topo->objs[ topo->links[ tile->in_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
44 0 : ctx->in_base = in_base;
45 0 : }
46 :
47 : static inline void
48 : during_frag( fd_udpecho_tile_ctx_t * ctx,
49 : ulong in_idx FD_PARAM_UNUSED,
50 : ulong seq,
51 : ulong sig FD_PARAM_UNUSED,
52 : ulong chunk,
53 : ulong sz,
54 0 : ulong ctl ) {
55 0 : FD_TEST( sz<=FD_NET_MTU );
56 0 : ctx->pkt_sz = 0;
57 :
58 0 : ulong const minsz = sizeof(fd_eth_hdr_t)+sizeof(fd_ip4_hdr_t)+sizeof(fd_udp_hdr_t);
59 0 : if( FD_UNLIKELY( sz<minsz ) ) return;
60 :
61 0 : uchar * frame_out = /* */fd_chunk_to_laddr ( ctx->out_base, ctx->chunk );
62 0 : void const * frame_in = (uchar const *)fd_chunk_to_laddr_const( ctx->in_base, chunk ) + ctl;
63 :
64 0 : fd_eth_hdr_t const * eth_hdr_in = fd_type_pun_const( frame_in );
65 0 : if( FD_UNLIKELY( fd_ushort_bswap( eth_hdr_in->net_type )!=FD_ETH_HDR_TYPE_IP ) ) return;
66 :
67 0 : fd_ip4_hdr_t const * ip4_hdr_in = fd_type_pun_const( (eth_hdr_in+1) );
68 0 : if( FD_UNLIKELY( FD_IP4_GET_VERSION( *ip4_hdr_in )!=4 ) ) return;
69 0 : ulong ip4_len = FD_IP4_GET_LEN( *ip4_hdr_in );
70 0 : ulong ip4_sz = fd_ushort_bswap( ip4_hdr_in->net_tot_len );
71 0 : sz = fd_ulong_min( sz, ip4_sz+sizeof(fd_eth_hdr_t) );
72 0 : if( FD_UNLIKELY( sz < sizeof(fd_eth_hdr_t)+ip4_len+sizeof(fd_udp_hdr_t) ) ) return;
73 0 : if( FD_UNLIKELY( ip4_hdr_in->protocol!=FD_IP4_HDR_PROTOCOL_UDP ) ) return;
74 :
75 0 : fd_udp_hdr_t const * udp_hdr_in = fd_type_pun_const( (ip4_hdr_in+1) );
76 0 : if( FD_UNLIKELY( fd_ushort_bswap( udp_hdr_in->net_len )<sizeof(fd_udp_hdr_t) ) ) return;
77 0 : ulong const udp_len = fd_ushort_bswap( udp_hdr_in->net_len );
78 0 : if( FD_UNLIKELY( udp_len<sizeof(fd_udp_hdr_t) ) ) return;
79 :
80 0 : void const * dgram_in = (udp_hdr_in+1);
81 0 : ulong const dgram_sz = udp_len-sizeof(fd_udp_hdr_t);
82 0 : if( FD_UNLIKELY( (ulong)dgram_in+dgram_sz > (ulong)frame_in+sz ) ) return;
83 :
84 0 : fd_eth_hdr_t eth_hdr_out = {
85 0 : .net_type = fd_ushort_bswap( FD_ETH_HDR_TYPE_IP )
86 0 : };
87 0 : FD_STORE( fd_eth_hdr_t, frame_out, eth_hdr_out );
88 0 : fd_ip4_hdr_t ip4_hdr = {
89 0 : .verihl = FD_IP4_VERIHL( 4, 5 ),
90 0 : .net_tot_len = fd_ushort_bswap( (ushort)( 28+dgram_sz ) ),
91 0 : .net_id = fd_ushort_bswap( (ushort)seq ),
92 0 : .net_frag_off = fd_ushort_bswap( FD_IP4_HDR_FRAG_OFF_DF ),
93 0 : .ttl = 64,
94 0 : .protocol = FD_IP4_HDR_PROTOCOL_UDP,
95 0 : .saddr = ip4_hdr_in->daddr,
96 0 : .daddr = ip4_hdr_in->saddr,
97 0 : };
98 0 : ip4_hdr.check = fd_ip4_hdr_check_fast( &ip4_hdr );
99 0 : ctx->ip4_dst = ip4_hdr.daddr;
100 0 : FD_STORE( fd_ip4_hdr_t, frame_out+14, ip4_hdr );
101 :
102 0 : fd_udp_hdr_t udp_hdr = {
103 0 : .net_sport = udp_hdr_in->net_dport,
104 0 : .net_dport = udp_hdr_in->net_sport,
105 0 : .net_len = udp_hdr_in->net_len
106 0 : };
107 0 : FD_STORE( fd_udp_hdr_t, frame_out+34, udp_hdr );
108 :
109 0 : fd_memcpy( frame_out+42, dgram_in, dgram_sz );
110 0 : ctx->pkt_sz = 42+dgram_sz;
111 0 : }
112 :
113 : static inline void
114 : after_frag( fd_udpecho_tile_ctx_t * ctx,
115 : ulong in_idx FD_PARAM_UNUSED,
116 : ulong in_seq FD_PARAM_UNUSED,
117 : ulong in_sig FD_PARAM_UNUSED,
118 : ulong in_sz FD_PARAM_UNUSED,
119 : ulong in_tsorig,
120 : ulong in_tspub FD_PARAM_UNUSED,
121 0 : fd_stem_context_t * stem ) {
122 0 : ulong out_sig = fd_disco_netmux_sig( 0U, 0, ctx->ip4_dst, DST_PROTO_OUTGOING, 42 );
123 0 : ulong out_chunk = ctx->chunk;
124 0 : ulong out_sz = ctx->pkt_sz;
125 0 : fd_stem_publish( stem, 0UL, out_sig, out_chunk, out_sz, 0, in_tsorig, 0UL );
126 0 : ctx->chunk = fd_dcache_compact_next( out_chunk, out_sz, ctx->chunk0, ctx->wmark );
127 0 : }
128 :
129 0 : #define STEM_BURST (1UL)
130 0 : #define STEM_LAZY ((long)10e6)
131 :
132 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_udpecho_tile_ctx_t
133 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_udpecho_tile_ctx_t)
134 :
135 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
136 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
137 :
138 : #include "../../../../disco/stem/fd_stem.c"
139 :
140 : fd_topo_run_tile_t fd_tile_udpecho = {
141 : .name = "l4swap",
142 : .scratch_align = scratch_align,
143 : .scratch_footprint = scratch_footprint,
144 : .unprivileged_init = unprivileged_init,
145 : .run = stem_run
146 : };
|