@@ -8,9 +8,10 @@ use std::net::{Ipv4Addr, SocketAddr};
88use std:: sync:: Arc ;
99use std:: time:: Duration ;
1010use tokio:: net:: UdpSocket ;
11- use tokio:: sync:: RwLock ;
11+ use tokio:: sync:: { Notify , RwLock } ;
1212use tokio:: time;
1313use tokio_tun:: TunBuilder ;
14+ use tokio_util:: sync:: CancellationToken ;
1415
1516const UDP_TTL : Duration = Duration :: from_secs ( 180 ) ;
1617
@@ -119,14 +120,16 @@ async fn main() {
119120 . parse ( )
120121 . expect ( "bad peer address for Tun interface" ) ;
121122
123+ let num_cpus = num_cpus:: get ( ) ;
124+
122125 let tun = TunBuilder :: new ( )
123126 . name ( matches. value_of ( "tun" ) . unwrap ( ) ) // if name is empty, then it is set by kernel.
124127 . tap ( false ) // false (default): TUN, true: TAP.
125128 . packet_info ( false ) // false: IFF_NO_PI, default is true.
126129 . up ( ) // or set it up manually using `sudo ip link set <tun-name> up`.
127130 . address ( tun_local)
128131 . destination ( tun_peer)
129- . try_build_mq ( num_cpus:: get ( ) )
132+ . try_build_mq ( num_cpus)
130133 . unwrap ( ) ;
131134
132135 info ! ( "Created TUN device {}" , tun[ 0 ] . name( ) ) ;
@@ -168,52 +171,85 @@ async fn main() {
168171 assert!( connections. write( ) . await . insert( addr, sock. clone( ) ) . is_none( ) ) ;
169172 debug!( "inserted fake TCP socket into connection table" ) ;
170173
171- let connections = connections. clone( ) ;
172-
173174 // spawn "fastpath" UDP socket and task, this will offload main task
174175 // 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( ) ;
180176
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 {
181233 loop {
182234 let read_timeout = time:: sleep( UDP_TTL ) ;
235+ let packet_received_fut = packet_received. notified( ) ;
183236
184237 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- } ,
210238 _ = read_timeout => {
211239 info!( "No traffic seen in the last {:?}, closing connection" , UDP_TTL ) ;
212240 connections. write( ) . await . remove( & addr) ;
213241 debug!( "removed fake TCP socket from connections table" ) ;
242+
243+ quit. cancel( ) ;
214244 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+ }
217253 }
218254 } ) ;
219255 } ,
0 commit comments