Skip to content

Allow direct use of interfaces in ExtLinks #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub enum Error {
Libnet(#[from] libnet::Error),
#[error("cli: {0}")]
Cli(String),
#[error("exclusive iface used multiple times: {0}")]
ExternalNicReused(String),
RonSpan(#[from] ron::error::SpannedError),
Ron(#[from] ron::Error),
TomL(#[from] toml::ser::Error),
Expand Down
87 changes: 74 additions & 13 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use ron::ser::{to_string_pretty, PrettyConfig};
use serde::{Deserialize, Serialize};
use slog::Drain;
use slog::{debug, error, info, warn, Logger};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::convert::TryInto;
use std::fs::{self, OpenOptions};
use std::io::BufWriter;
Expand Down Expand Up @@ -220,6 +220,7 @@ pub struct Link {
pub struct ExtLink {
pub endpoint: Endpoint,
pub host_ifx: String,
pub exclusive: bool,
}

/// Endpoint kind determines what type of device will be chosen to underpin a
Expand Down Expand Up @@ -458,17 +459,37 @@ impl Runner {
self.deployment.nodes[n.index].primary_disk_backing = backing
}

/// Create an external link attached to `host_ifx`.
/// Create an external link attached to `host_ifx` via a new VNIC.
pub fn ext_link(&mut self, host_ifx: impl AsRef<str>, n: NodeRef) {
self.ext_link_common(host_ifx, n, false);
}

/// Create an external link, consuming the link `host_ifx`.
pub fn ext_link_exclusive(
&mut self,
host_ifx: impl AsRef<str>,
n: NodeRef,
) {
self.ext_link_common(host_ifx, n, true);
}

fn ext_link_common(
&mut self,
host_ifx: impl AsRef<str>,
n: NodeRef,
exclusive: bool,
) {
let endpoint = Endpoint {
node: n,
index: self.deployment.nodes[n.index].radix,
kind: EndpointKind::Viona(None),
};
let host_ifx = host_ifx.as_ref().into();
self.deployment
.ext_links
.push(ExtLink { endpoint, host_ifx });
self.deployment.ext_links.push(ExtLink {
endpoint,
host_ifx,
exclusive,
});
self.deployment.nodes[n.index].radix += 1;
}

Expand Down Expand Up @@ -541,6 +562,26 @@ impl Runner {
)));
}

// validate that no external links are being jointly specified
// as exclusive and as parents of vnics.
let mut link_is_exclusive = HashMap::new();
for link in self.deployment.ext_links.iter() {
let entry = link_is_exclusive.entry(link.host_ifx.clone());

match entry {
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(link.exclusive);
}
Entry::Occupied(occupied_entry) => {
if link.exclusive || *occupied_entry.get() {
return Err(Error::ExternalNicReused(
link.host_ifx.clone(),
));
}
}
}
}

// ensure falcon working dir
fs::create_dir_all(&self.falcon_dir)?;

Expand Down Expand Up @@ -716,11 +757,25 @@ impl Deployment {

async fn nodes_preflight(&mut self, log: &Logger) -> Result<(), Error> {
let mut endpoints = Vec::new();

for l in &self.links {
endpoints.extend_from_slice(&l.endpoints);
for e in &l.endpoints {
endpoints.push(NodeEndpoint {
vnic_name: self.vnic_link_name(e),
endpoint: e.clone(),
});
}
}
for l in &self.ext_links {
endpoints.push(l.endpoint.clone());
let vnic_name = if l.exclusive {
l.host_ifx.clone()
} else {
self.vnic_link_name(&l.endpoint)
};
endpoints.push(NodeEndpoint {
vnic_name,
endpoint: l.endpoint.clone(),
})
}

let mut node_endpoints_map: HashMap<String, Vec<NodeEndpoint>> =
Expand All @@ -730,11 +785,8 @@ impl Deployment {
for n in self.nodes.iter() {
let node_endpoints: Vec<NodeEndpoint> = endpoints
.iter()
.filter(|e| self.nodes[e.node.index].name == n.name)
.map(|e| NodeEndpoint {
vnic_name: self.vnic_link_name(e),
endpoint: e.clone(),
})
.filter(|e| self.nodes[e.endpoint.node.index].name == n.name)
.cloned()
.collect();

let has_softnpu = node_endpoints.iter().any(|ne| {
Expand Down Expand Up @@ -771,6 +823,7 @@ impl Drop for Runner {
}
}

#[derive(Clone)]
struct NodeEndpoint {
vnic_name: String,
endpoint: Endpoint,
Expand Down Expand Up @@ -1470,6 +1523,10 @@ impl Link {

impl ExtLink {
fn create(&self, r: &Runner) -> Result<(), Error> {
if self.exclusive {
return Ok(());
}

let vnic_name = r.deployment.vnic_link_name(&self.endpoint);
let vnic = libnet::LinkHandle::Name(vnic_name.clone());
let host_ifx = libnet::LinkHandle::Name(self.host_ifx.clone());
Expand All @@ -1496,6 +1553,10 @@ impl ExtLink {
}

fn destroy(&self, r: &Runner) -> Result<(), Error> {
if self.exclusive {
return Ok(());
}

let vnic_name = r.deployment.vnic_link_name(&self.endpoint);
let vnic = libnet::LinkHandle::Name(vnic_name.clone());
info!(r.log, "destroying external link {}", &vnic_name);
Expand Down