44// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
55// Use of this source code is governed by a BSD-style license that can be
66// found in the THIRD-PARTY file.
7-
8- #[ cfg( not( test) ) ]
9- use std:: io;
107use std:: io:: { Read , Write } ;
118use std:: net:: Ipv4Addr ;
129use std:: sync:: atomic:: AtomicUsize ;
@@ -21,6 +18,7 @@ use mmds::ns::MmdsNetworkStack;
2118use rate_limiter:: { BucketUpdate , RateLimiter , TokenType } ;
2219use utils:: eventfd:: EventFd ;
2320use utils:: net:: mac:: { MacAddr , MAC_ADDR_LEN } ;
21+ use utils:: rand_bytes;
2422use virtio_gen:: virtio_net:: {
2523 virtio_net_hdr_v1, VIRTIO_F_VERSION_1 , VIRTIO_NET_F_CSUM , VIRTIO_NET_F_GUEST_CSUM ,
2624 VIRTIO_NET_F_GUEST_TSO4 , VIRTIO_NET_F_GUEST_UFO , VIRTIO_NET_F_HOST_TSO4 , VIRTIO_NET_F_HOST_UFO ,
@@ -49,6 +47,9 @@ enum FrontendError {
4947 ReadOnlyDescriptor ,
5048}
5149
50+ // KVM OUI MAC address is 52:54:00:xx:xx:xx
51+ const KVM_OUI : [ u8 ; 3 ] = [ 0x52 , 0x54 , 0x00 ] ;
52+
5253pub ( crate ) fn vnet_hdr_len ( ) -> usize {
5354 mem:: size_of :: < virtio_net_hdr_v1 > ( )
5455}
@@ -80,6 +81,14 @@ fn init_vnet_hdr(buf: &mut [u8]) {
8081 }
8182}
8283
84+ fn generate_mac_address ( ) -> MacAddr {
85+ let mut random_mac: [ u8 ; MAC_ADDR_LEN ] = [ 0 ; MAC_ADDR_LEN ] ;
86+ let ( left, right) = random_mac. split_at_mut ( 3 ) ;
87+ left. copy_from_slice ( & KVM_OUI ) ;
88+ right. copy_from_slice ( rand_bytes ( 3 ) . as_slice ( ) ) ;
89+ MacAddr :: from_bytes_unchecked ( & random_mac)
90+ }
91+
8392#[ derive( Clone , Copy ) ]
8493pub struct ConfigSpace {
8594 pub guest_mac : [ u8 ; MAC_ADDR_LEN ] ,
@@ -120,7 +129,7 @@ pub struct Net {
120129 pub ( crate ) irq_trigger : IrqTrigger ,
121130
122131 pub ( crate ) config_space : ConfigSpace ,
123- pub ( crate ) guest_mac : Option < MacAddr > ,
132+ pub ( crate ) guest_mac : MacAddr ,
124133
125134 pub ( crate ) device_state : DeviceState ,
126135 pub ( crate ) activate_evt : EventFd ,
@@ -162,12 +171,18 @@ impl Net {
162171 | 1 << VIRTIO_RING_F_EVENT_IDX ;
163172
164173 let mut config_space = ConfigSpace :: default ( ) ;
165- if let Some ( mac) = guest_mac {
166- config_space. guest_mac . copy_from_slice ( mac. get_bytes ( ) ) ;
167- // When this feature isn't available, the driver generates a random MAC address.
168- // Otherwise, it should attempt to read the device MAC address from the config space.
169- avail_features |= 1 << VIRTIO_NET_F_MAC ;
170- }
174+ // Enable feature to configure a MAC address
175+ // If not enabled, the driver generates a random MAC address.
176+ avail_features |= 1 << VIRTIO_NET_F_MAC ;
177+ let mac_addr = {
178+ if let Some ( some_mac_adrr) = guest_mac {
179+ * some_mac_adrr
180+ } else {
181+ // When the MAC address is not specified explicitly, generate one and assign it.
182+ generate_mac_address ( )
183+ }
184+ } ;
185+ config_space. guest_mac . copy_from_slice ( mac_addr. get_bytes ( ) ) ;
171186
172187 let mut queue_evts = Vec :: new ( ) ;
173188 let mut queues = Vec :: new ( ) ;
@@ -195,7 +210,7 @@ impl Net {
195210 activate_evt : EventFd :: new ( libc:: EFD_NONBLOCK ) . map_err ( Error :: EventFd ) ?,
196211 config_space,
197212 mmds_ns : None ,
198- guest_mac : guest_mac . copied ( ) ,
213+ guest_mac : mac_addr ,
199214
200215 #[ cfg( test) ]
201216 mocks : Mocks :: default ( ) ,
@@ -208,8 +223,8 @@ impl Net {
208223 }
209224
210225 /// Provides the MAC of this net device.
211- pub fn guest_mac ( & self ) -> Option < & MacAddr > {
212- self . guest_mac . as_ref ( )
226+ pub fn guest_mac ( & self ) -> & MacAddr {
227+ & self . guest_mac
213228 }
214229
215230 /// Provides the host IFACE name of this net device.
@@ -413,7 +428,7 @@ impl Net {
413428 rate_limiter : & mut RateLimiter ,
414429 frame_buf : & [ u8 ] ,
415430 tap : & mut Tap ,
416- guest_mac : Option < MacAddr > ,
431+ guest_mac : MacAddr ,
417432 ) -> Result < bool > {
418433 let checked_frame = |frame_buf| {
419434 frame_bytes_from_buf ( frame_buf) . map_err ( |err| {
@@ -438,13 +453,11 @@ impl Net {
438453 // This frame goes to the TAP.
439454
440455 // Check for guest MAC spoofing.
441- if let Some ( mac) = guest_mac {
442- let _ = EthernetFrame :: from_bytes ( checked_frame ( frame_buf) ?) . map ( |eth_frame| {
443- if mac != eth_frame. src_mac ( ) {
444- METRICS . net . tx_spoofed_mac_count . inc ( ) ;
445- }
446- } ) ;
447- }
456+ let _ = EthernetFrame :: from_bytes ( checked_frame ( frame_buf) ?) . map ( |eth_frame| {
457+ if guest_mac != eth_frame. src_mac ( ) {
458+ METRICS . net . tx_spoofed_mac_count . inc ( ) ;
459+ }
460+ } ) ;
448461
449462 match tap. write ( frame_buf) {
450463 Ok ( _) => {
@@ -661,7 +674,7 @@ impl Net {
661674 }
662675
663676 #[ cfg( not( test) ) ]
664- fn read_tap ( & mut self ) -> io:: Result < usize > {
677+ fn read_tap ( & mut self ) -> std :: io:: Result < usize > {
665678 self . tap . read ( & mut self . rx_frame_buf )
666679 }
667680
@@ -830,9 +843,8 @@ impl VirtioDevice for Net {
830843 }
831844
832845 config_space_bytes[ offset as usize ..( offset + data_len) as usize ] . copy_from_slice ( data) ;
833- self . guest_mac = Some ( MacAddr :: from_bytes_unchecked (
834- & self . config_space . guest_mac [ ..MAC_ADDR_LEN ] ,
835- ) ) ;
846+ self . guest_mac =
847+ MacAddr :: from_bytes_unchecked ( & self . config_space . guest_mac [ ..MAC_ADDR_LEN ] ) ;
836848 METRICS . net . mac_address_updates . inc ( ) ;
837849 }
838850
@@ -1003,7 +1015,7 @@ pub mod tests {
10031015
10041016 // Check that the guest MAC was updated.
10051017 let expected_guest_mac = MacAddr :: from_bytes_unchecked ( & new_config) ;
1006- assert_eq ! ( expected_guest_mac, net. guest_mac. unwrap ( ) ) ;
1018+ assert_eq ! ( expected_guest_mac, net. guest_mac) ;
10071019 assert_eq ! ( METRICS . net. mac_address_updates. count( ) , 1 ) ;
10081020
10091021 // Partial write (this is how the kernel sets a new mac address) - byte by byte.
@@ -1470,7 +1482,7 @@ pub mod tests {
14701482 & mut net. tx_rate_limiter,
14711483 & frame_buf[ ..frame_len] ,
14721484 & mut net. tap,
1473- Some ( src_mac) ,
1485+ src_mac,
14741486 )
14751487 . unwrap( ) )
14761488 ) ;
@@ -1504,7 +1516,7 @@ pub mod tests {
15041516 & mut net. tx_rate_limiter,
15051517 & frame_buf[ ..frame_len] ,
15061518 & mut net. tap,
1507- Some ( guest_mac) ,
1519+ guest_mac,
15081520 )
15091521 ) ;
15101522
@@ -1517,7 +1529,7 @@ pub mod tests {
15171529 & mut net. tx_rate_limiter,
15181530 & frame_buf[ ..frame_len] ,
15191531 & mut net. tap,
1520- Some ( not_guest_mac) ,
1532+ not_guest_mac,
15211533 )
15221534 ) ;
15231535 }
0 commit comments