use nlink::facade::Stack;
use nlink::netlink::config::NetworkConfig;
use nlink::netlink::nftables::config::NftablesConfig;
use nlink::netlink::nftables::{Family, Hook, Policy, Priority};
fn desired() -> Stack {
Stack::new()
.network(
NetworkConfig::new()
.link("stack0", |l| l.dummy().mtu(1400).up())
.address("stack0", "192.0.2.1/24")
.expect("valid CIDR"),
)
.nftables(NftablesConfig::new().table("stack_demo", Family::Inet, |t| {
t.chain("input", |c| {
c.hook(Hook::Input)
.priority(Priority::Filter)
.policy(Policy::Accept)
})
.rule("input", |r| r.match_iif("stack0").counter().accept())
}))
}
#[tokio::main]
async fn main() -> nlink::Result<()> {
let apply = std::env::args().any(|a| a == "--apply");
let stack = desired();
if !apply {
let net_only = Stack::new().network(desired().network.unwrap());
let diff = net_only.diff().await?;
println!(
"network layer drift: {} pending change(s)",
diff.change_count()
);
if let Some(net) = &diff.network {
print!("{net}");
}
println!("\nRe-run with --apply (as root) to converge all layers.");
return Ok(());
}
let report = stack.apply().await?;
println!(
"applied: {} kernel mutation(s) (noop = {})",
report.change_count(),
report.is_noop()
);
let again = stack.apply().await?;
println!(
"re-apply: {} mutation(s) (expect 0 → is_noop {})",
again.change_count(),
again.is_noop()
);
let conn = nlink::Connection::<nlink::Route>::new()?;
conn.del_link_if_exists("stack0").await?;
let nft = nlink::Connection::<nlink::Nftables>::new()?;
nft.del_table_if_exists("stack_demo", Family::Inet).await?;
println!("cleaned up stack0 + stack_demo table");
Ok(())
}