Link TAP interface to VM

Bug: 340376951
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid
--network-supported

Change-Id: I1937d9bd7393942541aa8c8e545a2aa7704de501
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index aeee6f7..d173b34 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -607,13 +607,20 @@
         };
 
         // Create TAP network interface if the VM supports network.
-        let _tap_fd = if cfg!(network) && config.networkSupported {
+        let tap = if cfg!(network) && config.networkSupported {
             if *is_protected {
                 return Err(anyhow!("Network feature is not supported for pVM yet"))
                     .with_log()
                     .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION)?;
             }
-            Some(GLOBAL_SERVICE.createTapInterface(&get_this_pid().to_string())?)
+            Some(File::from(
+                GLOBAL_SERVICE
+                    .createTapInterface(&get_this_pid().to_string())?
+                    .as_ref()
+                    .try_clone()
+                    .context("Failed to get TAP interface from ParcelFileDescriptor")
+                    .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?,
+            ))
         } else {
             None
         };
@@ -646,6 +653,7 @@
             display_config,
             input_device_options,
             hugepages: config.hugePages,
+            tap,
         };
         let instance = Arc::new(
             VmInstance::new(
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index d48ef7b..f73a977 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -122,6 +122,7 @@
     pub display_config: Option<DisplayConfig>,
     pub input_device_options: Vec<InputDeviceOption>,
     pub hugepages: bool,
+    pub tap: Option<File>,
 }
 
 #[derive(Debug)]
@@ -979,7 +980,7 @@
     }
 
     if cfg!(paravirtualized_devices) {
-        // TODO(b/325929096): Need to set up network from the config
+        // TODO(b/340376951): Remove this after tap in CrosvmConfig is connected to tethering.
         if rustutils::system_properties::read_bool("ro.crosvm.network.setup.done", false)
             .unwrap_or(false)
         {
@@ -987,6 +988,14 @@
         }
     }
 
+    if cfg!(network) {
+        if let Some(tap) = &config.tap {
+            let tap_fd = tap.as_raw_fd();
+            preserved_fds.push(tap_fd);
+            command.arg("--net").arg(format!("tap-fd={}", tap_fd));
+        }
+    }
+
     if cfg!(paravirtualized_devices) {
         for input_device_option in config.input_device_options.iter() {
             command.arg("--input");
diff --git a/virtualizationservice/vmnic/src/aidl.rs b/virtualizationservice/vmnic/src/aidl.rs
index ef1fda9..a206c25 100644
--- a/virtualizationservice/vmnic/src/aidl.rs
+++ b/virtualizationservice/vmnic/src/aidl.rs
@@ -17,7 +17,7 @@
 use anyhow::{anyhow, Context, Result};
 use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::IVmnic::IVmnic;
 use binder::{self, Interface, IntoBinderResult, ParcelFileDescriptor};
-use libc::{c_char, c_int, c_short, ifreq, IFF_NO_PI, IFF_TAP, IFF_UP, IFNAMSIZ};
+use libc::{c_char, c_int, c_short, ifreq, IFF_NO_PI, IFF_TAP, IFF_UP, IFF_VNET_HDR, IFNAMSIZ};
 use log::info;
 use nix::{ioctl_write_int_bad, ioctl_write_ptr_bad};
 use nix::sys::ioctl::ioctl_num_type;
@@ -47,7 +47,7 @@
 fn create_tap_interface(fd: RawFd, ifname: &[c_char]) -> Result<()> {
     // SAFETY: All-zero is a valid value for the ifreq type.
     let mut ifr: ifreq = unsafe { std::mem::zeroed() };
-    ifr.ifr_ifru.ifru_flags = (IFF_TAP | IFF_NO_PI) as c_short;
+    ifr.ifr_ifru.ifru_flags = (IFF_TAP | IFF_NO_PI | IFF_VNET_HDR) as c_short;
     ifr.ifr_name[..ifname.len()].copy_from_slice(ifname);
     // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
     // state of this process in any way.