@@ -20,8 +20,9 @@ use log::{debug, error, info, trace};
2020#[ cfg( not( fuzzing) ) ]
2121use net_util:: virtio_features_to_tap_offload;
2222use net_util:: {
23- CtrlQueue , MacAddr , NetCounters , NetQueuePair , OpenTapError , RxVirtio , Tap , TapError , TxVirtio ,
24- VirtioNetConfig , build_net_config_space, build_net_config_space_with_mq, open_tap,
23+ CtrlQueue , MAC_ADDR_LEN , MacAddr , NetCounters , NetQueuePair , OpenTapError , RxVirtio , Tap ,
24+ TapError , TxVirtio , VirtioNetConfig , build_net_config_space, build_net_config_space_with_mq,
25+ open_tap, vnet_hdr_len,
2526} ;
2627use seccompiler:: SeccompAction ;
2728use serde:: { Deserialize , Serialize } ;
@@ -40,6 +41,7 @@ use super::{
4041 EpollHelperHandler , Error as DeviceError , RateLimiterConfig , VirtioCommon , VirtioDevice ,
4142 VirtioDeviceType , VirtioInterruptType ,
4243} ;
44+ use crate :: device:: PostMigrationAnnouncer ;
4345use crate :: seccomp_filters:: Thread ;
4446use crate :: thread_helper:: spawn_virtio_thread;
4547use crate :: { GuestMemoryMmap , VirtioInterrupt } ;
@@ -655,6 +657,38 @@ impl Net {
655657 pub fn wait_for_epoll_threads ( & mut self ) {
656658 self . common . wait_for_epoll_threads ( ) ;
657659 }
660+
661+ fn build_rarp_announce ( & self ) -> [ u8 ; 60 ] {
662+ const ETH_P_RARP : u16 = 0x8035 ; // Ethertype RARP
663+ const ARP_HTYPE_ETH : u16 = 0x1 ; // Hardware type Ethernet
664+ const ARP_PTYPE_IP : u16 = 0x0800 ; // Protocol type IPv4
665+ const ARP_OP_REQUEST_REV : u16 = 0x0003 ; // RARP Request opcode
666+
667+ const IPV4_ADDR_LENGTH : usize = 4 ; // Size of an IPv4 address
668+
669+ let mut buf = [ 0u8 ; 60 ] ;
670+
671+ // Ethernet header
672+ buf[ 0 ..6 ] . copy_from_slice ( & [ 0xff ; MAC_ADDR_LEN ] ) ; // This is a broadcast
673+ buf[ 6 ..12 ] . copy_from_slice ( & self . config . mac ) ; // Src is this NIC
674+ buf[ 12 ..14 ] . copy_from_slice ( & ETH_P_RARP . to_be_bytes ( ) ) ; // This is a RARP packet
675+
676+ // ARP Header
677+ buf[ 14 ..16 ] . copy_from_slice ( & ARP_HTYPE_ETH . to_be_bytes ( ) ) ;
678+ buf[ 16 ..18 ] . copy_from_slice ( & ARP_PTYPE_IP . to_be_bytes ( ) ) ;
679+ buf[ 18 ] = MAC_ADDR_LEN as u8 ; // Hardware address length (ethernet)
680+ buf[ 19 ] = IPV4_ADDR_LENGTH as u8 ; // Protocol address length (IPv4)
681+ // This is a "fake RARP" packet, we don't want to perform a real RARP lookup.
682+ // Thus the content of the next fields is largely irrelevant. Setting source
683+ // hardware address = target hardware address is fine according to RFC 903.
684+ buf[ 20 ..22 ] . copy_from_slice ( & ARP_OP_REQUEST_REV . to_be_bytes ( ) ) ;
685+ buf[ 22 ..28 ] . copy_from_slice ( & self . config . mac ) ; // Source hardware address
686+ buf[ 28 ..32 ] . copy_from_slice ( & [ 0x00 ; IPV4_ADDR_LENGTH ] ) ; // Source protocol address
687+ buf[ 32 ..38 ] . copy_from_slice ( & self . config . mac ) ; // Target hardware address
688+ buf[ 38 ..42 ] . copy_from_slice ( & [ 0x00 ; IPV4_ADDR_LENGTH ] ) ; // Target protocol address
689+
690+ buf
691+ }
658692}
659693
660694impl Drop for Net {
@@ -870,6 +904,13 @@ impl VirtioDevice for Net {
870904 fn set_access_platform ( & mut self , access_platform : Arc < dyn AccessPlatform > ) {
871905 self . common . set_access_platform ( access_platform) ;
872906 }
907+
908+ fn post_migration_announcer ( & self ) -> std:: option:: Option < Box < dyn PostMigrationAnnouncer > > {
909+ Some ( Box :: new ( TapRarpAnnouncer :: new (
910+ self . build_rarp_announce ( ) ,
911+ self . taps . clone ( ) ,
912+ ) ) )
913+ }
873914}
874915
875916impl Pausable for Net {
@@ -898,3 +939,34 @@ impl Snapshottable for Net {
898939}
899940impl Transportable for Net { }
900941impl Migratable for Net { }
942+
943+ pub struct TapRarpAnnouncer {
944+ announce : [ u8 ; 60 ] ,
945+ taps : Vec < Tap > ,
946+ }
947+
948+ impl TapRarpAnnouncer {
949+ pub fn new ( announce : [ u8 ; 60 ] , taps : Vec < Tap > ) -> Self {
950+ Self { announce, taps }
951+ }
952+ }
953+
954+ impl PostMigrationAnnouncer for TapRarpAnnouncer {
955+ fn announce_once ( & mut self ) {
956+ // We have to add a virtio-net header to the announce.
957+ let mut buf = vec ! [ 0u8 ; vnet_hdr_len( ) + self . announce. len( ) ] ;
958+ buf[ vnet_hdr_len ( ) ..] . copy_from_slice ( & self . announce ) ;
959+
960+ for tap in & self . taps {
961+ // SAFETY: `buf.as_ptr()` is valid for `buf.len()` bytes and remains
962+ // valid until the syscall returns. `tap.as_raw_fd()` is a valid TAP fd.
963+ let _ = unsafe {
964+ libc:: write (
965+ tap. as_raw_fd ( ) ,
966+ buf. as_ptr ( ) as * const libc:: c_void ,
967+ buf. len ( ) ,
968+ )
969+ } ;
970+ }
971+ }
972+ }
0 commit comments