Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .github/workflows/core-build-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ jobs:
working-directory: cli
run: cargo test --locked

test-identity:
name: Test Identity
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Test Identity
working-directory: core
run: cargo test --locked -p cortexflow_identity

test-mcp:
name: Test MCP
runs-on: ubuntu-latest
Expand Down
183 changes: 172 additions & 11 deletions core/src/components/identity/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use nix::net::if_::if_nameindex;
use std::result::Result::Ok;
use tracing::info;
use tracing::{error, info};

// docs:
// This function checks if the given interface name is in the list of ignored interfaces
Expand All @@ -19,21 +19,84 @@ pub fn ignore_iface(iface: &str) -> bool {
//
#[inline(always)]
pub fn get_veth_channels() -> Vec<String> {
//filter interfaces and save the output in the
match if_nameindex() {
Ok(ifaces) => filter_veth_names(
ifaces
.iter()
.map(|iface| iface.name().to_string_lossy().into_owned()),
),
Err(_) => Vec::new(),
}
}

// Keeps only the interfaces that are not ignored, preserving order.
pub fn filter_veth_names<I>(names: I) -> Vec<String>
where
I: IntoIterator<Item = String>,
{
let mut interfaces: Vec<String> = Vec::new();
for iface_name in names {
if !ignore_iface(&iface_name) {
interfaces.push(iface_name);
} else {
info!("skipping interface {:?}", iface_name);
}
}
interfaces
}

// Packs an interface name and the "attached" state into the fixed-size key/value
// layout of the tracked_veth map (names longer than 16 bytes are truncated).
pub fn encode_link_entry(interface: &str) -> ([u8; 16], [u8; 8]) {
let mut if_bytes = [0u8; 16];
let interface_bytes = interface.as_bytes();
let len = interface_bytes.len().min(if_bytes.len());
if_bytes[..len].copy_from_slice(&interface_bytes[..len]);

let mut state_bytes = [0u8; 8];
let state = b"attached";
let state_len = state.len().min(state_bytes.len());
state_bytes[..state_len].copy_from_slice(&state[..state_len]);

if let Ok(ifaces) = if_nameindex() {
for iface in &ifaces {
let iface_name = iface.name().to_str().unwrap().to_owned();
if !ignore_iface(&iface_name) {
interfaces.push(iface_name);
} else {
info!("skipping interface {:?}", iface_name);
(if_bytes, state_bytes)
}

// Attaches the program to every interface and records successful attachments.
// Failures are logged and skipped. Returns the interfaces that were attached.
pub fn attach_and_register<A, I>(ifaces: Vec<String>, mut attach: A, mut insert: I) -> Vec<String>
where
A: FnMut(&str) -> Result<(), anyhow::Error>,
I: FnMut([u8; 16], [u8; 8]) -> Result<(), anyhow::Error>,
{
let mut attached = Vec::new();
for interface in ifaces {
match attach(&interface) {
std::result::Result::Ok(()) => {
info!(
"Program 'identity_classifier' attached to interface {}",
interface
);
let (key, value) = encode_link_entry(&interface);
match insert(key, value) {
std::result::Result::Ok(_) => {
info!("Veth interface {} added into map", &interface);
}
Err(e) => {
error!(
"Cannot add Veth interface {} into map. Reason: {}",
&interface, e
);
}
}
attached.push(interface);
}
Err(e) => error!(
"Error attaching program to interface {}: {:?}",
interface, e
),
}
}

interfaces
attached
}

#[cfg(test)]
Expand Down Expand Up @@ -62,4 +125,102 @@ mod tests {
};
assert_eq!(buffer.len(), 39);
}

use super::*;

#[test]
fn ignore_iface_matches_only_known_names() {
for n in ["eth0", "docker0", "tunl0", "lo"] {
assert!(ignore_iface(n));
}
assert!(!ignore_iface("veth123"));
assert!(!ignore_iface("eth01"));
assert!(!ignore_iface(""));
}

#[test]
fn filter_veth_names_drops_ignored_and_keeps_order() {
let input = ["lo", "veth1", "eth0", "veth2", "docker0", "tunl0", "cali3"]
.map(String::from);
assert_eq!(filter_veth_names(input), vec!["veth1", "veth2", "cali3"]);
}

#[test]
fn filter_veth_names_handles_empty_and_all_ignored() {
assert!(filter_veth_names(Vec::<String>::new()).is_empty());
assert!(filter_veth_names(["lo".to_string(), "eth0".to_string()]).is_empty());
}

#[test]
fn filter_veth_names_keeps_duplicates() {
let input = ["veth1", "veth1"].map(String::from);
assert_eq!(filter_veth_names(input).len(), 2);
}

#[test]
fn get_veth_channels_never_returns_ignored_interfaces() {
let channels = get_veth_channels();
assert!(channels.iter().all(|c| !ignore_iface(c)));
}

#[test]
fn encode_link_entry_pads_short_names() {
let (k, v) = encode_link_entry("veth0");
assert_eq!(&k[..5], b"veth0");
assert!(k[5..].iter().all(|b| *b == 0));
assert_eq!(&v, b"attached");
}

#[test]
fn encode_link_entry_truncates_long_names() {
let (k, _) = encode_link_entry("a_very_long_interface_name");
assert_eq!(&k, b"a_very_long_inte");
}

#[test]
fn attach_and_register_registers_every_attached_interface() {
let mut inserted = Vec::new();
let attached = attach_and_register(
vec!["veth0".into(), "veth1".into()],
|_| std::result::Result::Ok(()),
|k, v| {
inserted.push((k, v));
std::result::Result::Ok(())
},
);
assert_eq!(attached, vec!["veth0", "veth1"]);
assert_eq!(inserted.len(), 2);
assert_eq!(inserted[0], encode_link_entry("veth0"));
}

#[test]
fn attach_and_register_skips_failed_attachments() {
let mut inserted = 0;
let attached = attach_and_register(
vec!["bad".into(), "veth1".into()],
|i| if i == "bad" { Err(anyhow::anyhow!("boom")) } else { std::result::Result::Ok(()) },
|_, _| {
inserted += 1;
std::result::Result::Ok(())
},
);
assert_eq!(attached, vec!["veth1"]);
assert_eq!(inserted, 1);
}

#[test]
fn attach_and_register_survives_insert_failure() {
let attached = attach_and_register(
vec!["veth0".into(), "veth1".into()],
|_| std::result::Result::Ok(()),
|_, _| Err(anyhow::anyhow!("map full")),
);
assert_eq!(attached, vec!["veth0", "veth1"]);
}

#[test]
fn attach_and_register_handles_empty_list() {
let attached = attach_and_register(vec![], |_| Err(anyhow::anyhow!("unused")), |_, _| Err(anyhow::anyhow!("unused")));
assert!(attached.is_empty());
}
}
Loading
Loading