@@ -8,9 +8,10 @@ use std::net::{Ipv4Addr, SocketAddr};
8
8
use std:: sync:: Arc ;
9
9
use std:: time:: Duration ;
10
10
use tokio:: net:: UdpSocket ;
11
- use tokio:: sync:: RwLock ;
11
+ use tokio:: sync:: { Notify , RwLock } ;
12
12
use tokio:: time;
13
13
use tokio_tun:: TunBuilder ;
14
+ use tokio_util:: sync:: CancellationToken ;
14
15
15
16
const UDP_TTL : Duration = Duration :: from_secs ( 180 ) ;
16
17
@@ -119,14 +120,16 @@ async fn main() {
119
120
. parse ( )
120
121
. expect ( "bad peer address for Tun interface" ) ;
121
122
123
+ let num_cpus = num_cpus:: get ( ) ;
124
+
122
125
let tun = TunBuilder :: new ( )
123
126
. name ( matches. value_of ( "tun" ) . unwrap ( ) ) // if name is empty, then it is set by kernel.
124
127
. tap ( false ) // false (default): TUN, true: TAP.
125
128
. packet_info ( false ) // false: IFF_NO_PI, default is true.
126
129
. up ( ) // or set it up manually using `sudo ip link set <tun-name> up`.
127
130
. address ( tun_local)
128
131
. destination ( tun_peer)
129
- . try_build_mq ( num_cpus:: get ( ) )
132
+ . try_build_mq ( num_cpus)
130
133
. unwrap ( ) ;
131
134
132
135
info ! ( "Created TUN device {}" , tun[ 0 ] . name( ) ) ;
@@ -168,52 +171,85 @@ async fn main() {
168
171
assert!( connections. write( ) . await . insert( addr, sock. clone( ) ) . is_none( ) ) ;
169
172
debug!( "inserted fake TCP socket into connection table" ) ;
170
173
171
- let connections = connections. clone( ) ;
172
-
173
174
// spawn "fastpath" UDP socket and task, this will offload main task
174
175
// from forwarding UDP packets
175
- tokio:: spawn( async move {
176
- let mut buf_udp = [ 0u8 ; MAX_PACKET_LEN ] ;
177
- let mut buf_tcp = [ 0u8 ; MAX_PACKET_LEN ] ;
178
- let udp_sock = new_udp_reuseport( local_addr) ;
179
- udp_sock. connect( addr) . await . unwrap( ) ;
180
176
177
+ let packet_received = Arc :: new( Notify :: new( ) ) ;
178
+ let quit = CancellationToken :: new( ) ;
179
+
180
+ for i in 0 ..num_cpus {
181
+ let sock = sock. clone( ) ;
182
+ let quit = quit. child_token( ) ;
183
+ let packet_received = packet_received. clone( ) ;
184
+
185
+ tokio:: spawn( async move {
186
+ let mut buf_udp = [ 0u8 ; MAX_PACKET_LEN ] ;
187
+ let mut buf_tcp = [ 0u8 ; MAX_PACKET_LEN ] ;
188
+ let udp_sock = new_udp_reuseport( local_addr) ;
189
+ udp_sock. connect( addr) . await . unwrap( ) ;
190
+
191
+ loop {
192
+ tokio:: select! {
193
+ Ok ( size) = udp_sock. recv( & mut buf_udp) => {
194
+ if sock. send( & buf_udp[ ..size] ) . await . is_none( ) {
195
+ debug!( "removed fake TCP socket from connections table" ) ;
196
+ quit. cancel( ) ;
197
+ return ;
198
+ }
199
+
200
+ packet_received. notify_one( ) ;
201
+ } ,
202
+ res = sock. recv( & mut buf_tcp) => {
203
+ match res {
204
+ Some ( size) => {
205
+ if size > 0 {
206
+ if let Err ( e) = udp_sock. send( & buf_tcp[ ..size] ) . await {
207
+ error!( "Unable to send UDP packet to {}: {}, closing connection" , e, addr) ;
208
+ quit. cancel( ) ;
209
+ return ;
210
+ }
211
+ }
212
+ } ,
213
+ None => {
214
+ debug!( "removed fake TCP socket from connections table" ) ;
215
+ quit. cancel( ) ;
216
+ return ;
217
+ } ,
218
+ }
219
+
220
+ packet_received. notify_one( ) ;
221
+ } ,
222
+ _ = quit. cancelled( ) => {
223
+ debug!( "worker {} terminated" , i) ;
224
+ return ;
225
+ } ,
226
+ } ;
227
+ }
228
+ } ) ;
229
+ }
230
+
231
+ let connections = connections. clone( ) ;
232
+ tokio:: spawn( async move {
181
233
loop {
182
234
let read_timeout = time:: sleep( UDP_TTL ) ;
235
+ let packet_received_fut = packet_received. notified( ) ;
183
236
184
237
tokio:: select! {
185
- Ok ( size) = udp_sock. recv( & mut buf_udp) => {
186
- if sock. send( & buf_udp[ ..size] ) . await . is_none( ) {
187
- connections. write( ) . await . remove( & addr) ;
188
- debug!( "removed fake TCP socket from connections table" ) ;
189
- return ;
190
- }
191
- } ,
192
- res = sock. recv( & mut buf_tcp) => {
193
- match res {
194
- Some ( size) => {
195
- if size > 0 {
196
- if let Err ( e) = udp_sock. send( & buf_tcp[ ..size] ) . await {
197
- connections. write( ) . await . remove( & addr) ;
198
- error!( "Unable to send UDP packet to {}: {}, closing connection" , e, addr) ;
199
- return ;
200
- }
201
- }
202
- } ,
203
- None => {
204
- connections. write( ) . await . remove( & addr) ;
205
- debug!( "removed fake TCP socket from connections table" ) ;
206
- return ;
207
- } ,
208
- }
209
- } ,
210
238
_ = read_timeout => {
211
239
info!( "No traffic seen in the last {:?}, closing connection" , UDP_TTL ) ;
212
240
connections. write( ) . await . remove( & addr) ;
213
241
debug!( "removed fake TCP socket from connections table" ) ;
242
+
243
+ quit. cancel( ) ;
214
244
return ;
215
- }
216
- } ;
245
+ } ,
246
+ _ = quit. cancelled( ) => {
247
+ connections. write( ) . await . remove( & addr) ;
248
+ debug!( "removed fake TCP socket from connections table" ) ;
249
+ return ;
250
+ } ,
251
+ _ = packet_received_fut => { } ,
252
+ }
217
253
}
218
254
} ) ;
219
255
} ,
0 commit comments