summary refs log blame commit diff
path: root/pkgs/os-specific/linux/chromium-os/crosvm/VIRTIO_NET_F_MAC.patch
blob: 80cab56b1f8114b91db5d5d307a57201c66d0152 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
                                                                      

                                     
                                                                        









                                                                    
                                                        
                                                   
   
                                            
                                     


                                                                       

                                                                  
                                 

                               
                         

  
                          




                                     


                              

                                            
                                    

                                        


                                                    

                                                                    



                                                                                    
                                                                                         





                                         
                                                                           
 
                                                                                                
                          

                                                    
 
                                   


                                                                 
                 



                                                                                           
                          


                                                          



                                                   


                                                                               
                                          
                                 

                   
                                                 


      
                         




                                                            

                                       
                                                   
                                   

                            
                                              


                                                         
                                             
                               
                                






                                        
                                 

                  
                                                             

                                                     





                                                                                                    

                                                                                      
                                                                                         


       
                                                                                




                           

                                                                     
                                  
                                                                                                   



                                                                                        

                                                                                                   


                            
                                         
                                             

                                               


                                                                                                   

                                               

                                                                 









                                                                             
                                 

                 


                                                                                         
   





                                                                                             

                                                           
                                                                                               


                                                                                         

                        

                                                                                                        







                                                                 

                                                            











                                                                                   



































                                                                                               
                                                        


                                
                                                                                                      










                                                                                                                                                                                                                
      
 
From 2b5a83bd9e2c1c9642773c1daf785d03f95f33a3 Mon Sep 17 00:00:00 2001
From: Alyssa Ross <hi@alyssa.is>
Date: Sun, 27 Sep 2020 15:34:02 +0000
Subject: [PATCH crosvm v3] crosvm: support setting guest MAC from tap-fd

This adds a mac= option to crosvm's --tap-fd option.  The virtio-net
driver in the guest will read the desired MAC from virtio
configuration space.

See the documentation for VIRTIO_NET_F_MAC in the Virtio spec[1].

[1]: https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html

Thanks-to: Puck Meerburg <puck@puckipedia.com>
Reviewed-by: Cole Helbling <cole.e.helbling@outlook.com>
Message-Id: <20210517185700.3591932-1-hi@alyssa.is>
---
 devices/src/virtio/net.rs | 20 ++++++++++--
 src/crosvm.rs             |  8 +++--
 src/linux.rs              | 19 +++++++-----
 src/main.rs               | 64 +++++++++++++++++++++++++++++++--------
 4 files changed, 88 insertions(+), 23 deletions(-)

diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs
index b88dc44ae..b7489eb2b 100644
--- a/devices/src/virtio/net.rs
+++ b/devices/src/virtio/net.rs
@@ -419,6 +419,7 @@ where
 }
 
 pub struct Net<T: TapT> {
+    mac_address: Option<MacAddress>,
     queue_sizes: Box<[u16]>,
     workers_kill_evt: Vec<Event>,
     kill_evts: Vec<Event>,
@@ -439,6 +440,7 @@ where
         ip_addr: Ipv4Addr,
         netmask: Ipv4Addr,
         mac_addr: MacAddress,
+        guest_mac_addr: Option<MacAddress>,
         vq_pairs: u16,
     ) -> Result<Net<T>, NetError> {
         let multi_queue = vq_pairs > 1;
@@ -450,12 +452,17 @@ where
 
         tap.enable().map_err(NetError::TapEnable)?;
 
-        Net::from(base_features, tap, vq_pairs)
+        Net::with_tap(base_features, tap, vq_pairs, guest_mac_addr)
     }
 
     /// Creates a new virtio network device from a tap device that has already been
     /// configured.
-    pub fn from(base_features: u64, tap: T, vq_pairs: u16) -> Result<Net<T>, NetError> {
+    pub fn with_tap(
+        base_features: u64,
+        tap: T,
+        vq_pairs: u16,
+        mac_address: Option<MacAddress>,
+    ) -> Result<Net<T>, NetError> {
         let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?;
 
         // This would also validate a tap created by Self::new(), but that's a good thing as it
@@ -488,7 +495,12 @@ where
             workers_kill_evt.push(worker_kill_evt);
         }
 
+        if mac_address.is_some() {
+            avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
+        }
+
         Ok(Net {
+            mac_address,
             queue_sizes: vec![QUEUE_SIZE; (vq_pairs * 2 + 1) as usize].into_boxed_slice(),
             workers_kill_evt,
             kill_evts,
@@ -503,6 +515,10 @@ where
         let vq_pairs = self.queue_sizes.len() as u16 / 2;
 
         VirtioNetConfig {
+            mac: self
+                .mac_address
+                .map(|m| m.octets())
+                .unwrap_or_else(Default::default),
             max_vq_pairs: Le16::from(vq_pairs),
             // Other field has meaningful value when the corresponding feature
             // is enabled, but all these features aren't supported now.
diff --git a/src/crosvm.rs b/src/crosvm.rs
index eededc02e..62b3019db 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -191,6 +191,10 @@ impl Default for SharedDir {
     }
 }
 
+pub struct TapFdOption {
+    pub mac: Option<net_util::MacAddress>,
+}
+
 /// Aggregate of all configurable options for a running VM.
 pub struct Config {
     pub kvm_device_path: PathBuf,
@@ -217,7 +221,7 @@ pub struct Config {
     pub mac_address: Option<net_util::MacAddress>,
     pub net_vq_pairs: Option<u16>,
     pub vhost_net: bool,
-    pub tap_fd: Vec<RawFd>,
+    pub tap_fd: BTreeMap<RawFd, TapFdOption>,
     pub cid: Option<u64>,
     pub wayland_socket_paths: BTreeMap<String, PathBuf>,
     pub wayland_dmabuf: bool,
@@ -291,7 +295,7 @@ impl Default for Config {
             mac_address: None,
             net_vq_pairs: None,
             vhost_net: false,
-            tap_fd: Vec::new(),
+            tap_fd: BTreeMap::new(),
             cid: None,
             #[cfg(feature = "gpu")]
             gpu_parameters: None,
diff --git a/src/linux.rs b/src/linux.rs
index ba2d28f96..e9601478a 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -60,8 +60,8 @@ use vm_memory::{GuestAddress, GuestMemory};
 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
 use crate::gdb::{gdb_thread, GdbStub};
 use crate::{
-    Config, DiskOption, Executable, SharedDir, SharedDirKind, TouchDeviceOption, VhostUserFsOption,
-    VhostUserOption,
+    Config, DiskOption, Executable, SharedDir, SharedDirKind, TapFdOption, TouchDeviceOption,
+    VhostUserFsOption, VhostUserOption,
 };
 use arch::{
     self, LinuxArch, RunnableLinuxVm, SerialHardware, SerialParameters, VcpuAffinity,
@@ -763,7 +763,11 @@ fn create_balloon_device(cfg: &Config, tube: Tube) -> DeviceResult {
     })
 }
 
-fn create_tap_net_device(cfg: &Config, tap_fd: RawDescriptor) -> DeviceResult {
+fn create_tap_net_device(
+    cfg: &Config,
+    tap_fd: RawDescriptor,
+    options: &TapFdOption,
+) -> DeviceResult {
     // Safe because we ensure that we get a unique handle to the fd.
     let tap = unsafe {
         Tap::from_raw_descriptor(
@@ -779,7 +783,8 @@ fn create_tap_net_device(cfg: &Config, tap_fd: RawDescriptor) -> DeviceResult {
         vq_pairs = 1;
     }
     let features = virtio::base_features(cfg.protected_vm);
-    let dev = virtio::Net::from(features, tap, vq_pairs).map_err(Error::NetDeviceNew)?;
+    let dev =
+        virtio::Net::with_tap(features, tap, vq_pairs, options.mac).map_err(Error::NetDeviceNew)?;
 
     Ok(VirtioDeviceStub {
         dev: Box::new(dev),
@@ -814,7 +819,7 @@ fn create_net_device(
         .map_err(Error::VhostNetDeviceNew)?;
         Box::new(dev) as Box<dyn VirtioDevice>
     } else {
-        let dev = virtio::Net::<Tap>::new(features, host_ip, netmask, mac_address, vq_pairs)
+        let dev = virtio::Net::<Tap>::new(features, host_ip, netmask, mac_address, None, vq_pairs)
             .map_err(Error::NetDeviceNew)?;
         Box::new(dev) as Box<dyn VirtioDevice>
     };
@@ -1445,8 +1450,8 @@ fn create_virtio_devices(
     devs.push(create_balloon_device(cfg, balloon_device_tube)?);
 
     // We checked above that if the IP is defined, then the netmask is, too.
-    for tap_fd in &cfg.tap_fd {
-        devs.push(create_tap_net_device(cfg, *tap_fd)?);
+    for (tap_fd, options) in &cfg.tap_fd {
+        devs.push(create_tap_net_device(cfg, *tap_fd, options)?);
     }
 
     if let (Some(host_ip), Some(netmask), Some(mac_address)) =
diff --git a/src/main.rs b/src/main.rs
index ab62f2543..e1188a86c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,13 +20,15 @@ use arch::{
     set_default_serial_parameters, Pstore, SerialHardware, SerialParameters, SerialType,
     VcpuAffinity,
 };
-use base::{debug, error, getpid, info, kill_process_group, reap_child, syslog, warn};
+use base::{
+    debug, error, getpid, info, kill_process_group, reap_child, syslog, warn, RawDescriptor,
+};
 #[cfg(feature = "direct")]
 use crosvm::DirectIoOption;
 use crosvm::{
     argument::{self, print_help, set_arguments, Argument},
-    platform, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption,
-    VhostUserFsOption, VhostUserOption, DISK_ID_LEN,
+    platform, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TapFdOption,
+    TouchDeviceOption, VhostUserFsOption, VhostUserOption, DISK_ID_LEN,
 };
 #[cfg(feature = "gpu")]
 use devices::virtio::gpu::{GpuMode, GpuParameters};
@@ -1460,17 +1462,55 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
         }
         "vhost-net" => cfg.vhost_net = true,
         "tap-fd" => {
-            cfg.tap_fd.push(
-                value
-                    .unwrap()
-                    .parse()
-                    .map_err(|_| argument::Error::InvalidValue {
+            let mut components = value.unwrap().split(',');
+
+            let fd: RawDescriptor =
+                components
+                    .next()
+                    .and_then(|x| x.parse().ok())
+                    .ok_or_else(|| argument::Error::InvalidValue {
                         value: value.unwrap().to_owned(),
                         expected: String::from(
                             "this value for `tap-fd` must be an unsigned integer",
                         ),
-                    })?,
-            );
+                    })?;
+
+            let mut mac = None;
+            for c in components {
+                let mut kv = c.splitn(2, '=');
+                let (kind, value) = match (kv.next(), kv.next()) {
+                    (Some(kind), Some(value)) => (kind, value),
+                    _ => {
+                        return Err(argument::Error::InvalidValue {
+                            value: c.to_owned(),
+                            expected: String::from("option must be of the form `kind=value`"),
+                        })
+                    }
+                };
+                match kind {
+                    "mac" => {
+                        mac = Some(value.parse().map_err(|_| argument::Error::InvalidValue {
+                            value: value.to_owned(),
+                            expected: String::from(
+                                "`mac` needs to be in the form \"XX:XX:XX:XX:XX:XX\"",
+                            ),
+                        })?)
+                    }
+                    _ => {
+                        return Err(argument::Error::InvalidValue {
+                            value: kind.to_owned(),
+                            expected: String::from("unrecognized option"),
+                        })
+                    }
+                }
+            }
+            if cfg.tap_fd.contains_key(&fd) {
+                return Err(argument::Error::TooManyArguments(format!(
+                    "TAP FD already used: '{}'",
+                    name
+                )));
+            }
+            cfg.tap_fd.insert(fd, TapFdOption { mac });
         }
         #[cfg(feature = "gpu")]
         "gpu" => {
@@ -1907,8 +1947,8 @@ writeback=BOOL - Indicates whether the VM can use writeback caching (default: fa
           Argument::value("plugin-gid-map-file", "PATH", "Path to the file listing supplemental GIDs that should be mapped in plugin jail.  Can be given more than once."),
           Argument::flag("vhost-net", "Use vhost for networking."),
           Argument::value("tap-fd",
-                          "fd",
-                          "File descriptor for configured tap device. A different virtual network card will be added each time this argument is given."),
+                          "FD[,mac=MAC]",
+                          "File descriptor for configured tap device. A different virtual network card will be added each time this argument is given. MAC is the MAC address that will be set in the guest."),
           #[cfg(feature = "gpu")]
           Argument::flag_or_value("gpu",
                                   "[width=INT,height=INT]",
-- 
2.31.1