@@ -151,9 +151,6 @@ pub struct NetEpollHandler {
151151 acked_features : u64 ,
152152 mmds_ns : Option < MmdsNetworkStack > ,
153153 guest_mac : Option < MacAddr > ,
154- epoll_fd : RawFd ,
155- rx_tap_listening : bool ,
156- rx_tap_epoll_token : u64 ,
157154
158155 #[ cfg( test) ]
159156 test_mutators : tests:: TestMutators ,
@@ -477,7 +474,7 @@ impl NetEpollHandler {
477474 self . tx . queue . add_used ( & self . mem , head_index, 0 ) ;
478475 raise_irq = true ;
479476 }
480-
477+
481478 if raise_irq {
482479 self . signal_used_queue ( ) ?;
483480 }
@@ -506,28 +503,6 @@ impl NetEpollHandler {
506503 fn read_tap ( & mut self ) -> io:: Result < usize > {
507504 self . tap . read ( & mut self . rx . frame_buf )
508505 }
509-
510- fn register_tap_rx_listener ( & mut self ) -> std:: result:: Result < ( ) , std:: io:: Error > {
511- epoll:: ctl (
512- self . epoll_fd ,
513- epoll:: ControlOptions :: EPOLL_CTL_ADD ,
514- self . tap . as_raw_fd ( ) ,
515- epoll:: Event :: new ( epoll:: Events :: EPOLLIN , self . rx_tap_epoll_token ) ,
516- ) ?;
517- self . rx_tap_listening = true ;
518- Ok ( ( ) )
519- }
520-
521- fn unregister_tap_rx_listener ( & mut self ) -> std:: result:: Result < ( ) , std:: io:: Error > {
522- epoll:: ctl (
523- self . epoll_fd ,
524- epoll:: ControlOptions :: EPOLL_CTL_DEL ,
525- self . tap . as_raw_fd ( ) ,
526- epoll:: Event :: new ( epoll:: Events :: EPOLLIN , self . rx_tap_epoll_token ) ,
527- ) ?;
528- self . rx_tap_listening = false ;
529- Ok ( ( ) )
530- }
531506}
532507
533508impl EpollHandler for NetEpollHandler {
@@ -547,10 +522,6 @@ impl EpollHandler for NetEpollHandler {
547522 underlying : e,
548523 } )
549524 } else {
550- if !self . rx_tap_listening {
551- self . register_tap_rx_listener ( )
552- . map_err ( DeviceError :: IoError ) ?;
553- }
554525 // If the limiter is not blocked, resume the receiving of bytes.
555526 if !self . rx . rate_limiter . is_blocked ( ) {
556527 // There should be a buffer available now to receive the frame into.
@@ -564,8 +535,6 @@ impl EpollHandler for NetEpollHandler {
564535 METRICS . net . rx_tap_event_count . inc ( ) ;
565536
566537 if self . rx . queue . is_empty ( & self . mem ) {
567- self . unregister_tap_rx_listener ( )
568- . map_err ( DeviceError :: IoError ) ?;
569538 return Err ( DeviceError :: NoAvailBuffers ) ;
570539 }
571540
@@ -827,6 +796,8 @@ impl VirtioDevice for Net {
827796 } else {
828797 None
829798 } ;
799+ let tap_fd = tap. as_raw_fd ( ) ;
800+
830801 let handler = NetEpollHandler {
831802 rx : RxVirtio :: new (
832803 rx_queue,
@@ -845,9 +816,6 @@ impl VirtioDevice for Net {
845816 acked_features : self . acked_features ,
846817 mmds_ns,
847818 guest_mac : self . guest_mac ( ) ,
848- epoll_fd : self . epoll_config . epoll_raw_fd ,
849- rx_tap_listening : false ,
850- rx_tap_epoll_token : self . epoll_config . rx_tap_token ,
851819
852820 #[ cfg( test) ]
853821 test_mutators : tests:: TestMutators :: default ( ) ,
@@ -867,6 +835,20 @@ impl VirtioDevice for Net {
867835
868836 //TODO: barrier needed here maybe?
869837
838+ epoll:: ctl (
839+ self . epoll_config . epoll_raw_fd ,
840+ epoll:: ControlOptions :: EPOLL_CTL_ADD ,
841+ tap_fd,
842+ epoll:: Event :: new (
843+ epoll:: Events :: EPOLLIN | epoll:: Events :: EPOLLET ,
844+ self . epoll_config . rx_tap_token ,
845+ ) ,
846+ )
847+ . map_err ( |e| {
848+ METRICS . net . activate_fails . inc ( ) ;
849+ ActivateError :: EpollCtl ( e)
850+ } ) ?;
851+
870852 epoll:: ctl (
871853 self . epoll_config . epoll_raw_fd ,
872854 epoll:: ControlOptions :: EPOLL_CTL_ADD ,
@@ -1130,7 +1112,6 @@ mod tests {
11301112 let interrupt_evt = EventFd :: new ( libc:: EFD_NONBLOCK ) . unwrap ( ) ;
11311113 let rx_queue_evt = EventFd :: new ( libc:: EFD_NONBLOCK ) . unwrap ( ) ;
11321114 let tx_queue_evt = EventFd :: new ( libc:: EFD_NONBLOCK ) . unwrap ( ) ;
1133- let epoll_fd = epoll:: create ( true ) . unwrap ( ) ;
11341115
11351116 (
11361117 NetEpollHandler {
@@ -1144,9 +1125,6 @@ mod tests {
11441125 mmds_ns : Some ( MmdsNetworkStack :: new_with_defaults ( ) ) ,
11451126 test_mutators,
11461127 guest_mac : None ,
1147- epoll_fd,
1148- rx_tap_epoll_token : 0 ,
1149- rx_tap_listening : false ,
11501128 } ,
11511129 txq,
11521130 rxq,
@@ -1482,15 +1460,12 @@ mod tests {
14821460 } ;
14831461 let mem = GuestMemory :: new ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
14841462 let ( mut h, _txq, rxq) = default_test_netepollhandler ( & mem, test_mutators) ;
1485- h. register_tap_rx_listener ( ) . unwrap ( ) ;
14861463
14871464 // The RX queue is empty.
14881465 match h. handle_event ( RX_TAP_EVENT , epoll:: Events :: EPOLLIN ) {
14891466 Err ( DeviceError :: NoAvailBuffers ) => ( ) ,
14901467 _ => panic ! ( "invalid" ) ,
14911468 }
1492- // Since the RX was empty, we shouldn't be listening for tap RX events.
1493- assert ! ( !h. rx_tap_listening) ;
14941469
14951470 // Fake an avail buffer; this time, tap reading should error out.
14961471 rxq. avail . idx . set ( 1 ) ;
@@ -1711,8 +1686,8 @@ mod tests {
17111686 }
17121687
17131688 // wait for 100ms to give the rate-limiter timer a chance to replenish
1714- // wait for an extra 50ms to make sure the timerfd event makes its way from the kernel
1715- thread:: sleep ( Duration :: from_millis ( 150 ) ) ;
1689+ // wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
1690+ thread:: sleep ( Duration :: from_millis ( 200 ) ) ;
17161691
17171692 // following TX procedure should succeed because bandwidth should now be available
17181693 {
@@ -1762,8 +1737,8 @@ mod tests {
17621737 }
17631738
17641739 // wait for 100ms to give the rate-limiter timer a chance to replenish
1765- // wait for an extra 50ms to make sure the timerfd event makes its way from the kernel
1766- thread:: sleep ( Duration :: from_millis ( 150 ) ) ;
1740+ // wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
1741+ thread:: sleep ( Duration :: from_millis ( 200 ) ) ;
17671742
17681743 // following RX procedure should succeed because bandwidth should now be available
17691744 {
@@ -1819,8 +1794,8 @@ mod tests {
18191794 }
18201795
18211796 // wait for 100ms to give the rate-limiter timer a chance to replenish
1822- // wait for an extra 50ms to make sure the timerfd event makes its way from the kernel
1823- thread:: sleep ( Duration :: from_millis ( 150 ) ) ;
1797+ // wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
1798+ thread:: sleep ( Duration :: from_millis ( 200 ) ) ;
18241799
18251800 // following TX procedure should succeed because ops should now be available
18261801 {
@@ -1874,8 +1849,8 @@ mod tests {
18741849 }
18751850
18761851 // wait for 100ms to give the rate-limiter timer a chance to replenish
1877- // wait for an extra 50ms to make sure the timerfd event makes its way from the kernel
1878- thread:: sleep ( Duration :: from_millis ( 150 ) ) ;
1852+ // wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
1853+ thread:: sleep ( Duration :: from_millis ( 200 ) ) ;
18791854
18801855 // following RX procedure should succeed because ops should now be available
18811856 {
@@ -1924,4 +1899,28 @@ mod tests {
19241899 compare_buckets ( h. get_tx_rate_limiter ( ) . bandwidth ( ) . unwrap ( ) , & tx_bytes) ;
19251900 compare_buckets ( h. get_tx_rate_limiter ( ) . ops ( ) . unwrap ( ) , & tx_ops) ;
19261901 }
1902+
1903+ #[ test]
1904+ fn test_tx_queue_interrupt ( ) {
1905+ // Regression test for https://github.com/firecracker-microvm/firecracker/issues/1436 .
1906+ let mem = GuestMemory :: new ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
1907+ let ( mut h, txq, _) = default_test_netepollhandler ( & mem, TestMutators :: default ( ) ) ;
1908+
1909+ let daddr = 0x2000 ;
1910+ assert ! ( daddr > txq. end( ) . 0 ) ;
1911+
1912+ // Do some TX.
1913+ txq. avail . idx . set ( 1 ) ;
1914+ txq. avail . ring [ 0 ] . set ( 0 ) ;
1915+ txq. dtable [ 0 ] . set ( daddr, 0x1000 , 0 , 0 ) ;
1916+
1917+ // trigger the TX handler
1918+ h. tx . queue_evt . write ( 1 ) . unwrap ( ) ;
1919+ h. handle_event ( TX_QUEUE_EVENT , EPOLLIN ) . unwrap ( ) ;
1920+
1921+ // Verify if TX queue was processed.
1922+ assert_eq ! ( txq. used. idx. get( ) , 1 ) ;
1923+ // Check if interrupt was triggered.
1924+ assert_eq ! ( h. interrupt_evt. read( ) . unwrap( ) , 1 ) ;
1925+ }
19271926}
0 commit comments