diff --git a/src/runtime-rs/crates/resource/src/network/endpoint/ipvlan_endpoint.rs b/src/runtime-rs/crates/resource/src/network/endpoint/ipvlan_endpoint.rs new file mode 100644 index 0000000000..5f31002786 --- /dev/null +++ b/src/runtime-rs/crates/resource/src/network/endpoint/ipvlan_endpoint.rs @@ -0,0 +1,90 @@ +// Copyright (c) 2019-2022 Alibaba Cloud +// Copyright (c) 2019-2022 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::io::{self, Error}; + +use anyhow::{Context, Result}; +use async_trait::async_trait; + +use super::Endpoint; +use crate::network::network_model::TC_FILTER_NET_MODEL_STR; +use crate::network::{utils, NetworkPair}; +use hypervisor::{device::NetworkConfig, Device, Hypervisor}; + +// IPVlanEndpoint is the endpoint bridged to VM +#[derive(Debug)] +pub struct IPVlanEndpoint { + pub(crate) net_pair: NetworkPair, +} + +impl IPVlanEndpoint { + pub async fn new( + handle: &rtnetlink::Handle, + name: &str, + idx: u32, + queues: usize, + ) -> Result { + // tc filter network model is the only one works for ipvlan + let net_pair = NetworkPair::new(handle, idx, name, TC_FILTER_NET_MODEL_STR, queues) + .await + .context("error creating new NetworkPair")?; + Ok(IPVlanEndpoint { net_pair }) + } + + fn get_network_config(&self) -> Result { + let iface = &self.net_pair.tap.tap_iface; + let guest_mac = utils::parse_mac(&iface.hard_addr).ok_or_else(|| { + Error::new( + io::ErrorKind::InvalidData, + format!("hard_addr {}", &iface.hard_addr), + ) + })?; + Ok(NetworkConfig { + id: self.net_pair.virt_iface.name.clone(), + host_dev_name: iface.name.clone(), + guest_mac: Some(guest_mac), + }) + } +} + +#[async_trait] +impl Endpoint for IPVlanEndpoint { + async fn name(&self) -> String { + self.net_pair.virt_iface.name.clone() + } + + async fn hardware_addr(&self) -> String { + self.net_pair.tap.tap_iface.hard_addr.clone() + } + + async fn attach(&self, h: &dyn Hypervisor) -> Result<()> { + self.net_pair + .add_network_model() + .await + .context("error adding network model")?; + let config = self.get_network_config().context("get network config")?; + h.add_device(Device::Network(config)) + .await + .context("error adding device by hypervisor")?; + + Ok(()) + } + + async fn detach(&self, h: &dyn Hypervisor) -> Result<()> { + self.net_pair + .del_network_model() + .await + .context("error deleting network model")?; + let config = self + .get_network_config() + .context("error getting network config")?; + h.remove_device(Device::Network(config)) + .await + .context("error removing device by hypervisor")?; + + Ok(()) + } +} diff --git a/src/runtime-rs/crates/resource/src/network/endpoint/mod.rs b/src/runtime-rs/crates/resource/src/network/endpoint/mod.rs index caaa69dca6..c55182f54f 100644 --- a/src/runtime-rs/crates/resource/src/network/endpoint/mod.rs +++ b/src/runtime-rs/crates/resource/src/network/endpoint/mod.rs @@ -8,6 +8,8 @@ mod physical_endpoint; pub use physical_endpoint::PhysicalEndpoint; mod veth_endpoint; pub use veth_endpoint::VethEndpoint; +mod ipvlan_endpoint; +pub use ipvlan_endpoint::IPVlanEndpoint; use anyhow::Result; use async_trait::async_trait; diff --git a/src/runtime-rs/crates/resource/src/network/network_model/mod.rs b/src/runtime-rs/crates/resource/src/network/network_model/mod.rs index 848e032c0a..16457f1e4f 100644 --- a/src/runtime-rs/crates/resource/src/network/network_model/mod.rs +++ b/src/runtime-rs/crates/resource/src/network/network_model/mod.rs @@ -15,8 +15,8 @@ use async_trait::async_trait; use super::NetworkPair; -const TC_FILTER_NET_MODEL_STR: &str = "tcfilter"; -const ROUTE_NET_MODEL_STR: &str = "route"; +pub(crate) const TC_FILTER_NET_MODEL_STR: &str = "tcfilter"; +pub(crate) const ROUTE_NET_MODEL_STR: &str = "route"; pub enum NetworkModelType { NoneModel, diff --git a/src/runtime-rs/crates/resource/src/network/network_pair.rs b/src/runtime-rs/crates/resource/src/network/network_pair.rs index 71e212907e..c96898619b 100644 --- a/src/runtime-rs/crates/resource/src/network/network_pair.rs +++ b/src/runtime-rs/crates/resource/src/network/network_pair.rs @@ -54,6 +54,7 @@ impl NetworkPair { let tap_link = create_link(handle, &tap_iface_name, queues) .await .context("create link")?; + let virt_link = get_link_by_name(handle, virt_iface_name.clone().as_str()) .await .context("get link by name")?; diff --git a/src/runtime-rs/crates/resource/src/network/network_with_netns.rs b/src/runtime-rs/crates/resource/src/network/network_with_netns.rs index c8c76b6e25..1d2a1e55f9 100644 --- a/src/runtime-rs/crates/resource/src/network/network_with_netns.rs +++ b/src/runtime-rs/crates/resource/src/network/network_with_netns.rs @@ -17,7 +17,7 @@ use scopeguard::defer; use tokio::sync::RwLock; use super::{ - endpoint::{Endpoint, PhysicalEndpoint, VethEndpoint}, + endpoint::{Endpoint, IPVlanEndpoint, PhysicalEndpoint, VethEndpoint}, network_entity::NetworkEntity, network_info::network_info_from_link::NetworkInfoFromLink, utils::{link, netns}, @@ -186,6 +186,12 @@ async fn create_endpoint( .context("veth endpoint")?; Arc::new(ret) } + "ipvlan" => { + let ret = IPVlanEndpoint::new(handle, &attrs.name, idx, config.queues) + .await + .context("ipvlan endpoint")?; + Arc::new(ret) + } _ => return Err(anyhow!("unsupported link type: {}", link_type)), } };