Instead of grabbing commands from files, the daemon now connects to the brain and receives commands via gRPC. Reviewed-on: SNP/daemon#2
177 lines
5.1 KiB
Rust
177 lines
5.1 KiB
Rust
#![allow(dead_code)]
|
|
use anyhow::Result;
|
|
use serde::Deserialize;
|
|
use std::{
|
|
net::{Ipv4Addr, Ipv6Addr},
|
|
ops::Range,
|
|
};
|
|
|
|
#[derive(Deserialize, Debug, Clone)]
|
|
pub struct Volume {
|
|
pub path: String,
|
|
pub max_reservation_gb: usize,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct IPv4Range {
|
|
pub first_ip: Ipv4Addr,
|
|
pub last_ip: Ipv4Addr,
|
|
pub netmask: String,
|
|
pub gateway: Ipv4Addr,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct IPv6Range {
|
|
pub first_ip: Ipv6Addr,
|
|
pub last_ip: Ipv6Addr,
|
|
pub netmask: String,
|
|
pub gateway: Ipv6Addr,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Interface {
|
|
pub driver: InterfaceType,
|
|
pub device: String,
|
|
pub ipv4_ranges: Vec<IPv4Range>,
|
|
pub ipv6_ranges: Vec<IPv6Range>,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub enum InterfaceType {
|
|
MACVTAP,
|
|
IPVTAP,
|
|
Bridge,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Config {
|
|
pub brain_url: String,
|
|
pub max_cores_per_vm: usize,
|
|
pub max_vcpu_reservation: usize,
|
|
pub max_mem_reservation_mb: usize,
|
|
pub network_interfaces: Vec<Interface>,
|
|
pub volumes: Vec<Volume>,
|
|
#[serde(with = "range_format")]
|
|
pub public_port_range: Range<u16>,
|
|
pub max_ports_per_vm: u16,
|
|
}
|
|
|
|
mod range_format {
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
use std::ops::Range;
|
|
|
|
pub fn serialize<S>(range: &Range<u16>, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
let range_repr = RangeRepr { start: range.start, end: range.end };
|
|
range_repr.serialize(serializer)
|
|
}
|
|
|
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Range<u16>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let range_repr = RangeRepr::deserialize(deserializer)?;
|
|
Ok(range_repr.start..range_repr.end)
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct RangeRepr {
|
|
start: u16,
|
|
end: u16,
|
|
}
|
|
}
|
|
|
|
impl Config {
|
|
pub fn load_from_disk(path: &str) -> Result<Self> {
|
|
let content = std::fs::read_to_string(path)?;
|
|
let config: Config = serde_yaml::from_str(&content)?;
|
|
for nic in &config.network_interfaces {
|
|
for range in &nic.ipv4_ranges {
|
|
let ipv4_netmask = range.netmask.parse::<u8>()?;
|
|
if ipv4_netmask > 32 {
|
|
return Err(anyhow::anyhow!(
|
|
"IPv4 netmask must be in short format: a number from 1 to 32"
|
|
));
|
|
}
|
|
if range.first_ip.to_bits() > range.last_ip.to_bits() {
|
|
return Err(anyhow::anyhow!(
|
|
"For range {range:?} first ip is bigger than last ip."
|
|
));
|
|
}
|
|
let expected_netmask = std::cmp::min(
|
|
calc_ipv4_netmask(range.first_ip, range.gateway),
|
|
calc_ipv4_netmask(range.last_ip, range.gateway),
|
|
);
|
|
if expected_netmask < ipv4_netmask as u32 {
|
|
return Err(anyhow::anyhow!(
|
|
"Your netmask is too small to include the IPs and also the gateway: {range:?}"
|
|
));
|
|
}
|
|
}
|
|
for range in &nic.ipv6_ranges {
|
|
let ipv6_netmask = range.netmask.parse::<u8>()?;
|
|
if ipv6_netmask > 128 {
|
|
return Err(anyhow::anyhow!(
|
|
"IPv6 netmask must be in short format: a number from 1 to 128"
|
|
));
|
|
}
|
|
if range.first_ip.to_bits() > range.last_ip.to_bits() {
|
|
return Err(anyhow::anyhow!(
|
|
"For range {range:?} first ip is bigger than last ip."
|
|
));
|
|
}
|
|
let expected_netmask = std::cmp::min(
|
|
calc_ipv6_netmask(range.first_ip, range.gateway),
|
|
calc_ipv6_netmask(range.last_ip, range.gateway),
|
|
);
|
|
if expected_netmask < ipv6_netmask as u128 {
|
|
return Err(anyhow::anyhow!(
|
|
"Your netmask is too small to include the IPs and also the gateway: {range:?}"
|
|
));
|
|
}
|
|
}
|
|
}
|
|
Ok(config)
|
|
}
|
|
}
|
|
|
|
fn calc_ipv4_netmask(ip: Ipv4Addr, gateway: Ipv4Addr) -> u32 {
|
|
// Convert the IPs to u32 for easier bit manipulation
|
|
let ip_u32 = u32::from(ip);
|
|
let gateway_u32 = u32::from(gateway);
|
|
|
|
// Find the smallest common prefix
|
|
let mut prefix_len = 0;
|
|
for i in 1..=32 {
|
|
if (ip_u32 >> (32 - i)) == (gateway_u32 >> (32 - i)) {
|
|
prefix_len = i;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return the mask as a string
|
|
prefix_len
|
|
}
|
|
|
|
fn calc_ipv6_netmask(ip: Ipv6Addr, gateway: Ipv6Addr) -> u128 {
|
|
// Convert the IPs to u128 for easier bit manipulation
|
|
let ip_u128 = u128::from(ip);
|
|
let gateway_u128 = u128::from(gateway);
|
|
|
|
// Find the smallest common prefix
|
|
let mut prefix_len = 0;
|
|
for i in 1..=128 {
|
|
if (ip_u128 >> (128 - i)) == (gateway_u128 >> (128 - i)) {
|
|
prefix_len = i;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return the mask as a string
|
|
prefix_len
|
|
}
|