Skip to content

Commit

Permalink
feat: get internet access (virt-do#39)
Browse files Browse the repository at this point in the history
* feat: create bridge interface

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>

* feat: create bridge only if not exist

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>

* fix: cargo clippy

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>

* feat: send code though gRPC to the agent (virt-do#37)

* feat(agent/proto): add agent configuration in execute request

Signed-off-by: Martin Moreira de Jesus <martin.moreira-de-jesus@protonmail.com>

* feat: send code through cli and api to vm

Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>

---------

Signed-off-by: Martin Moreira de Jesus <martin.moreira-de-jesus@protonmail.com>
Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>
Co-authored-by: Martin Moreira de Jesus <martin.moreira-de-jesus@protonmail.com>

* Feat: add initramfs implementation for vmm (virt-do#34)

* feat(vmm): implemented automatic generation of rootfs with initramfs

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* feat: image generation based off language

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* feat(vmm): implemented automatic generation of rootfs with initramfs

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* fix(vmm): fix logging & language order

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* feat(vmm): one image per language

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* feat(vmm): implemented initramfs

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* fix(vmm): code cleanup

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* fix(vmm): code cleanup

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* fix(vmm): code cleanup

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>

* fix: rust export for cargo agent and increase MMIO_GAP_END

Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>

* chore: lint

Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>

* fix: add back tracing

Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>

---------

Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>
Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>
Co-authored-by: Mauran <thomas.mauran@etu.umontpellier.fr>

* feat: internet works

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>

* fix: cargo clippy

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>

---------

Signed-off-by: sylvain-pierrot <sylvain.pierrot@etu.umontpellier.fr>
Signed-off-by: Martin Moreira de Jesus <martin.moreira-de-jesus@protonmail.com>
Signed-off-by: Mauran <thomas.mauran@etu.umontpellier.fr>
Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>
Co-authored-by: Thomas Mauran <78204354+thomas-mauran@users.noreply.github.com>
Co-authored-by: Martin Moreira de Jesus <martin.moreira-de-jesus@protonmail.com>
Co-authored-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>
Co-authored-by: Mauran <thomas.mauran@etu.umontpellier.fr>
Signed-off-by: Muriel Paraire <72733662+MurielParaire@users.noreply.github.com>
  • Loading branch information
5 people committed May 3, 2024
1 parent cfdb10d commit 3c3bceb
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ run:
'RUST_BACKTRACE=1 '$CARGO_PATH' run --bin vmm -- cli --memory 512 --cpus 1 \
--kernel tools/kernel/linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin \
--iface-host-addr 172.29.0.1 --netmask 255.255.0.0 --iface-guest-addr 172.29.0.2 \
--initramfs=tools/rootfs/initramfs.img'
--initramfs=../virt-do/initramfs.img'

build-kernel:
#!/bin/bash
Expand Down
2 changes: 2 additions & 0 deletions src/fs-gen/resources/initfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export RUST_VERSION='1.77.2'

export PATH=$CARGO_HOME/bin:$PATH

ln -s /proc/net/pnp /etc/resolv.conf

/agent

reboot
5 changes: 4 additions & 1 deletion src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ clap = { version = "4.5.1", features = ["derive", "env"] }
clap-verbosity-flag = "2.2.0"
epoll = "4.3.3"
event-manager = { version = "0.4.0", features = ["remote_endpoint"] }
futures = "0.3.30"
iptables = "0.5.1"
kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] }
kvm-ioctls = "0.16.0"
libc = "0.2.153"
Expand All @@ -22,7 +24,9 @@ log = "0.4.20"
nix = { version = "0.28.0", features = ["term"] }
openpty = "0.2.0"
prost = "0.11"
rtnetlink = "0.14.1"
tokio = { version = "1.37.0", features = ["full"] }
tokio-stream = "0.1.15"
tonic = "0.9"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
Expand All @@ -34,7 +38,6 @@ vm-device = "0.1.0"
vm-memory = { version = "0.14.1", features = ["backend-mmap"] }
vm-superio = "0.7.0"
vmm-sys-util = "0.12.1"
tokio-stream = "0.1.15"

[build-dependencies]
tonic-build = "0.9"
137 changes: 137 additions & 0 deletions src/vmm/src/core/devices/virtio/net/bridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::net::{IpAddr, Ipv4Addr};

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle};

use super::xx_netmask_width;

#[derive(Clone)]
pub struct Bridge {
name: String,
handle: Handle,
}

impl Bridge {
pub fn new(name: String) -> Self {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

let br = Self { name, handle };
br.create_bridge_if_not_exist();

br
}

fn create_bridge_if_not_exist(&self) {
futures::executor::block_on(async {
let mut bridge_names = self
.handle
.link()
.get()
.match_name(self.name.clone())
.execute();

let _ = match bridge_names.try_next().await {
Ok(_) => Ok(()),
Err(_) => self
.handle
.link()
.add()
.bridge(self.name.clone())
.execute()
.await
.map_err(|_| Error::RequestFailed),
};
});
}

pub fn set_addr(&self, addr: Ipv4Addr, netmask: Ipv4Addr) {
futures::executor::block_on(async {
let mut bridge_names = self
.handle
.link()
.get()
.match_name(self.name.clone())
.execute();

let bridge_index = match bridge_names.try_next().await {
Ok(Some(link)) => link.header.index,
Ok(None) => panic!(),
Err(_) => panic!(),
};

let prefix_len = xx_netmask_width(netmask.octets());

let _ = self
.handle
.address()
.add(bridge_index, IpAddr::V4(addr), prefix_len)
.execute()
.await
.map_err(|_| Error::RequestFailed);
});
}

pub fn set_up(&self) {
futures::executor::block_on(async {
let mut bridge_names = self
.handle
.link()
.get()
.match_name(self.name.clone())
.execute();

let bridge_index = match bridge_names.try_next().await {
Ok(Some(link)) => link.header.index,
Ok(None) => panic!(),
Err(_) => panic!(),
};

let _ = self
.handle
.link()
.set(bridge_index)
.up()
.execute()
.await
.map_err(|_| Error::RequestFailed);
});
}

pub fn attach_link(&self, link_name: String) {
futures::executor::block_on(async {
let mut link_names = self
.handle
.link()
.get()
.match_name(link_name.clone())
.execute();
let mut master_names = self
.handle
.link()
.get()
.match_name(self.name.clone())
.execute();

let link_index = match link_names.try_next().await {
Ok(Some(link)) => link.header.index,
Ok(None) => panic!(),
Err(_) => panic!(),
};
let master_index = match master_names.try_next().await {
Ok(Some(link)) => link.header.index,
Ok(None) => panic!(),
Err(_) => panic!(),
};

let _ = self
.handle
.link()
.set(link_index)
.controller(master_index)
.execute()
.await
.map_err(|_| Error::RequestFailed);
});
}
}
24 changes: 18 additions & 6 deletions src/vmm/src/core/devices/virtio/net/device.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use super::bridge::Bridge;
use super::iptables::iptables_ip_masq;
use super::queue_handler::QueueHandler;
use super::{
simple_handler::SimpleHandler, tuntap::tap::Tap, Error, Result, NET_DEVICE_ID,
Expand Down Expand Up @@ -34,6 +36,7 @@ pub struct Net {
mem: Arc<GuestMemoryMmap>,
pub config: Config,
tap: Arc<Mutex<Tap>>,
_bridge: Bridge,
}

impl Net {
Expand All @@ -42,7 +45,7 @@ impl Net {
mem: Arc<GuestMemoryMmap>,
device_mgr: Arc<Mutex<IoManager>>,
mmio_cfg: MmioConfig,
tap_addr: Ipv4Addr,
iface_host_addr: Ipv4Addr,
netmask: Ipv4Addr,
iface_guest_addr: Ipv4Addr,
irq: u32,
Expand Down Expand Up @@ -74,25 +77,34 @@ impl Net {

// Set offload flags to match the relevant virtio features of the device (for now,
// statically set in the constructor.
let tap = open_tap(None, Some(tap_addr), Some(netmask), &mut None, None, None)
.map_err(Error::TunTap)?;
let tap = open_tap(None, None, None, &mut None, None, None).map_err(Error::TunTap)?;

// The layout of the header is specified in the standard and is 12 bytes in size. We
// should define this somewhere.
tap.set_vnet_hdr_size(VIRTIO_NET_HDR_SIZE as i32)
.map_err(Error::Tap)?;

let bridge_name = "br0".to_string();
let bridge = Bridge::new(bridge_name.clone());
bridge.set_addr(iface_host_addr, netmask);
bridge.attach_link(tap.get_name().map_err(Error::Tap)?);
bridge.set_up();

// Get internet access
iptables_ip_masq(iface_host_addr & netmask, netmask, bridge_name);

let net = Arc::new(Mutex::new(Net {
mem,
config: cfg,
tap: Arc::new(Mutex::new(tap)),
tap: Arc::new(Mutex::new(tap.clone())),
_bridge: bridge,
}));

let vmmio_param = register_mmio_device(mmio_cfg, device_mgr, irq, None, net.clone())
.map_err(Error::Virtio)?;
let ip_pnp_param: String = format!(
"ip={}::{}:{}::eth0:off",
iface_guest_addr, tap_addr, netmask
"ip={}::{}:{}::eth0:off:1.1.1.1",
iface_guest_addr, iface_host_addr, netmask
);

cmdline_extra_parameters.push(vmmio_param);
Expand Down
16 changes: 16 additions & 0 deletions src/vmm/src/core/devices/virtio/net/iptables.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::net::Ipv4Addr;

use super::xx_netmask_width;

pub fn iptables_ip_masq(network: Ipv4Addr, netmask: Ipv4Addr, link_name: String) {
let prefix_len = xx_netmask_width(netmask.octets());
let source = format!("{}/{}", network, prefix_len);

let ipt = iptables::new(false).unwrap();
let rule = format!("-s {} ! -o {} -j MASQUERADE", source, link_name);

let exists = ipt.exists("nat", "POSTROUTING", rule.as_str()).unwrap();
if !exists {
let _ = ipt.insert_unique("nat", "POSTROUTING", rule.as_str(), 1);
}
}
6 changes: 6 additions & 0 deletions src/vmm/src/core/devices/virtio/net/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod bridge;
pub mod device;
pub mod iptables;
mod queue_handler;
mod simple_handler;
pub mod tuntap;
Expand All @@ -20,3 +22,7 @@ pub enum Error {
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn xx_netmask_width<const SZ: usize>(netmask: [u8; SZ]) -> u8 {
netmask.iter().map(|x| x.count_ones() as u8).sum()
}
6 changes: 6 additions & 0 deletions src/vmm/src/core/devices/virtio/net/tuntap/tap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ impl Tap {
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) }
}

/// Get tap name
pub fn get_name(&self) -> Result<String> {
let name = String::from_utf8(self.if_name.clone()).map_err(|_| Error::InvalidIfname)?;
Ok(name)
}

/// Get mac addr for tap interface.
pub fn get_mac_addr(&self) -> Result<MacAddr> {
let sock = create_unix_socket().map_err(Error::NetUtil)?;
Expand Down
12 changes: 8 additions & 4 deletions src/vmm/src/core/vmm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub struct VMM {
event_mgr: EventMgr,
vcpus: Vec<Vcpu>,

tap_addr: Ipv4Addr,
iface_host_addr: Ipv4Addr,
netmask: Ipv4Addr,
iface_guest_addr: Ipv4Addr,
net_devices: Vec<Arc<Mutex<Net>>>,
Expand All @@ -69,7 +69,11 @@ pub struct VMM {

impl VMM {
/// Create a new VMM.
pub fn new(tap_addr: Ipv4Addr, netmask: Ipv4Addr, iface_guest_addr: Ipv4Addr) -> Result<Self> {
pub fn new(
iface_host_addr: Ipv4Addr,
netmask: Ipv4Addr,
iface_guest_addr: Ipv4Addr,
) -> Result<Self> {
// Open /dev/kvm and get a file descriptor to it.
let kvm = Kvm::new().map_err(Error::KvmIoctl)?;

Expand Down Expand Up @@ -111,7 +115,7 @@ impl VMM {
)),
slip_pty: Arc::new(Mutex::new(slip_pty)),
epoll,
tap_addr,
iface_host_addr,
netmask,
iface_guest_addr,
net_devices: Vec::new(),
Expand Down Expand Up @@ -382,7 +386,7 @@ impl VMM {
mem,
self.device_mgr.clone(),
mmio_cfg,
self.tap_addr,
self.iface_host_addr,
self.netmask,
self.iface_guest_addr,
irq,
Expand Down

0 comments on commit 3c3bceb

Please sign in to comment.