some virtual-router config work

This commit is contained in:
Christien Rioux 2024-11-11 22:11:20 -05:00
parent 9fe8f0f102
commit f2aa066626
8 changed files with 388 additions and 6 deletions

6
Cargo.lock generated
View File

@ -2874,6 +2874,9 @@ name = "ipnet"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
dependencies = [
"serde",
]
[[package]]
name = "ipnetwork"
@ -6555,6 +6558,8 @@ dependencies = [
"backtrace",
"cfg-if 1.0.0",
"chrono",
"clap 4.5.20",
"config 0.13.4",
"console_error_panic_hook",
"ctrlc",
"eyre",
@ -6564,6 +6569,7 @@ dependencies = [
"futures_codec",
"getrandom",
"ifstructs",
"ipnet",
"jni",
"jni-sys",
"js-sys",

View File

@ -44,7 +44,13 @@ tracing = ["dep:tracing", "dep:tracing-subscriber", "tokio/tracing"]
debug-locks = []
virtual-network = []
virtual-network-server = ["dep:ws_stream_tungstenite", "dep:async-tungstenite"]
virtual-network-server = [
"dep:ws_stream_tungstenite",
"dep:async-tungstenite",
"dep:clap",
"dep:config",
"dep:ipnet",
]
[dependencies]
tracing = { version = "0.1.40", features = [
@ -95,8 +101,14 @@ socket2 = { version = "0.5.7", features = ["all"] }
tokio = { version = "1.38.1", features = ["full"], optional = true }
tokio-util = { version = "0.7.11", features = ["compat"], optional = true }
tokio-stream = { version = "0.1.15", features = ["net"], optional = true }
ws_stream_tungstenite = { version = "0.14.0", optional = true }
async-tungstenite = { version = "0.28.0", optional = true }
clap = { version = "4", features = ["derive"], optional = true }
config = { version = "^0", default-features = false, features = [
"yaml",
], optional = true }
ipnet = { version = "2", features = ["serde"], optional = true }
# Dependencies for WASM builds only
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]

View File

@ -1,7 +1,9 @@
#![cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use cfg_if::*;
use clap::Parser;
use parking_lot::*;
use std::path::PathBuf;
use stop_token::StopSource;
use veilid_tools::*;
@ -23,12 +25,33 @@ cfg_if! {
}
}
#[derive(Parser, Debug)]
#[command(author, version, about = "Veilid VirtualRouter")]
struct CmdlineArgs {
/// TCP address to listen on
#[arg(short('t'), long)]
tcp_addr: Option<SocketAddr>,
/// Turn off TCP listener
#[arg(long)]
no_tcp: bool,
/// WS address to listen on
#[arg(short('w'), long)]
ws_addr: Option<SocketAddr>,
/// Turn off WS listener
#[arg(long)]
no_ws: bool,
/// Specify a configuration file to use
#[arg(short = 'c', long, value_name = "FILE")]
config_file: Option<PathBuf>,
}
fn main() -> Result<(), String> {
let stop_source = StopSource::new();
let stop_token = stop_source.token();
let stop_mutex = Mutex::new(Some(stop_source));
ctrlc::set_handler(move || {
println!("Exiting...");
*(stop_mutex.lock()) = None;
})
.expect("Error setting Ctrl-C handler");
@ -36,7 +59,31 @@ fn main() -> Result<(), String> {
block_on(async {
println!("Veilid VirtualRouter v{}", VERSION);
let args = CmdlineArgs::parse();
let router_server = virtual_network::RouterServer::new();
let _ss_tcp = if !args.no_tcp {
Some(
router_server
.listen_tcp(args.tcp_addr)
.await
.map_err(|e| e.to_string())?,
)
} else {
None
};
let _ss_ws = if !args.no_ws {
Some(
router_server
.listen_ws(args.ws_addr)
.await
.map_err(|e| e.to_string())?,
)
} else {
None
};
router_server
.run(stop_token)
.await

View File

@ -46,7 +46,9 @@ impl fmt::Display for VirtualProtocolType {
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum ServerProcessorRequest {
AllocateMachine,
AllocateMachine {
profile: String,
},
ReleaseMachine {
machine_id: MachineId,
},

View File

@ -180,8 +180,8 @@ impl RouterClient {
}
}
pub async fn allocate_machine(self) -> VirtualNetworkResult<MachineId> {
let request = ServerProcessorRequest::AllocateMachine;
pub async fn allocate_machine(self, profile: String) -> VirtualNetworkResult<MachineId> {
let request = ServerProcessorRequest::AllocateMachine { profile };
let ServerProcessorReplyValue::AllocateMachine { machine_id } =
self.perform_request(request).await?
else {

View File

@ -0,0 +1,168 @@
use super::*;
use ipnet::*;
use serde::*;
use std::ffi::OsStr;
use std::path::Path;
pub use ::config::ConfigError;
fn load_default_config() -> Result<::config::Config, ConfigError> {
let default_config = include_str!("default_config.yml");
::config::Config::builder()
.add_source(::config::File::from_str(
default_config,
::config::FileFormat::Yaml,
))
.build()
}
fn load_config(cfg: ::config::Config, config_file: &Path) -> Result<::config::Config, ConfigError> {
if let Some(config_file_str) = config_file.to_str() {
::config::Config::builder()
.add_source(cfg)
.add_source(::config::File::new(
config_file_str,
::config::FileFormat::Yaml,
))
.build()
} else {
Err(ConfigError::Message(
"config file path is not valid UTF-8".to_owned(),
))
}
}
const fn default_weight() -> f32 {
1.0f32
}
#[derive(Debug, Clone, Deserialize)]
pub struct Profile {
machine: One<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Machine {
network: One<String>,
#[serde(default)]
address4: Option<Ipv4Addr>,
#[serde(default)]
address6: Option<Ipv6Addr>,
#[serde(default)]
disable_capabilities: Vec<String>,
#[serde(default)]
bootstrap: bool,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct One<T: fmt::Debug + Clone> {
#[serde(flatten)]
pub value: Vec<Weighted<T>>,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct OneOrNone<T: fmt::Debug + Clone> {
#[serde(flatten)]
pub value: Vec<Weighted<T>>,
#[serde(default = "default_weight")]
pub none_weight: f32,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Probability {
#[serde(flatten)]
probability: f32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Weighted<T: fmt::Debug + Clone> {
#[serde(flatten)]
pub value: T,
#[serde(default = "default_weight")]
pub weight: f32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Network {
#[serde(flatten)]
subnets: Subnets,
#[serde(default)]
distance: Option<Distance>,
#[serde(flatten)]
performance: Performance,
#[serde(default)]
gateway: Option<Gateway>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Subnets {
subnet4: OneOrNone<Ipv4Net>,
subnet6: OneOrNone<Ipv6Net>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Gateway {
translation: One<Translation>,
upnp: Probability,
network: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Distance {
min: f32,
max: f32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Distribution {
mean: f32,
sigma: f32,
skew: f32,
min: f32,
max: f32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Decay {
lambda: f32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Performance {
latency: Distribution,
loss: Probability,
}
#[derive(Debug, Clone, Deserialize)]
pub enum Translation {
None,
PortRestricted,
AddressRestricted,
Symmetric,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
seed: Option<u32>,
profiles: HashMap<String, Profile>,
machines: HashMap<String, Machine>,
networks: HashMap<String, Network>,
}
impl Config {
pub fn new(config_file: Option<&OsStr>) -> Result<Self, ConfigError> {
// Load the default config
let mut cfg = load_default_config()?;
// Merge in the config file if we have one
if let Some(config_file) = config_file {
let config_file_path = Path::new(config_file);
// If the user specifies a config file on the command line then it must exist
cfg = load_config(cfg, config_file_path)?;
}
// Generate config
cfg.try_deserialize()
}
}

View File

@ -0,0 +1,43 @@
---
seed: 0
profiles:
- default:
- bootstrap:
- server:
machines:
- bootstrap-1.veilid.net:
network: "boot"
address4: "170.64.128.16"
address6: "2a03:b0c0:2:dd::ddd:0010"
disable_capabilities:
["ROUT", "TUNL", "SGNL", "RLAY", "DIAL", "DHTV", "DHTW", "APPM"]
bootstrap: true
- bootstrap-2.veilid.net:
network: "boot"
address4: "170.64.128.17"
address6: "2a03:b0c0:2:dd::ddd:0011"
disable_capabilities:
["ROUT", "TUNL", "SGNL", "RLAY", "DIAL", "DHTV", "DHTW", "APPM"]
bootstrap: true
networks:
- internet:
distance:
min: 0.04
max: 2.0
latency:
mean: 0.200
sigma: 0.080
skew: 0
min: 0.030
max: 0.400
loss: 0.01
- boot:
subnet4: ["170.64.128.0/24"]
subnet6: ["2a03:b0c0:2::/48"]
latency:
mean: 0.0038
sigma: 0.001416
skew: 0.0009
min: 0.0015
max: 0.0075
loss: 0.0

View File

@ -1,3 +1,5 @@
mod config;
use super::*;
use async_tungstenite::accept_async;
use futures_codec::{Bytes, BytesCodec, FramedRead, FramedWrite};
@ -139,7 +141,7 @@ impl RouterServer {
.new_client_sender
.send(inbound_receiver_fut)
{
// Error register connection processor
// Error registering connection processor
error!("{}", e);
break;
}
@ -201,7 +203,7 @@ impl RouterServer {
.new_client_sender
.send(inbound_receiver_fut)
{
// Error register connection processor
// Error registering connection processor
error!("{}", e);
break;
}
@ -310,10 +312,112 @@ impl RouterServer {
self,
cmd: ServerProcessorCommand,
outbound_sender: flume::Sender<ServerProcessorEvent>,
) -> RouterServerResult<()> {
match cmd {
ServerProcessorCommand::Message(server_processor_message) => {
self.process_message(
server_processor_message.message_id,
server_processor_message.request,
outbound_sender,
)
.await
}
ServerProcessorCommand::CloseSocket {
machine_id,
socket_id,
} => {
self.process_close_socket(machine_id, socket_id, outbound_sender)
.await
}
}
}
async fn process_close_socket(
self,
machine_id: MachineId,
socket_id: SocketId,
outbound_sender: flume::Sender<ServerProcessorEvent>,
) -> RouterServerResult<()> {
//
Ok(())
}
async fn process_message(
self,
message_id: MessageId,
request: ServerProcessorRequest,
outbound_sender: flume::Sender<ServerProcessorEvent>,
) -> RouterServerResult<()> {
match request {
ServerProcessorRequest::AllocateMachine { profile } => todo!(),
ServerProcessorRequest::ReleaseMachine { machine_id } => todo!(),
ServerProcessorRequest::GetInterfaces { machine_id } => todo!(),
ServerProcessorRequest::TcpConnect {
machine_id,
local_address,
remote_address,
timeout_ms,
options,
} => todo!(),
ServerProcessorRequest::TcpBind {
machine_id,
local_address,
options,
} => todo!(),
ServerProcessorRequest::TcpAccept {
machine_id,
listen_socket_id,
} => todo!(),
ServerProcessorRequest::TcpShutdown {
machine_id,
socket_id,
} => todo!(),
ServerProcessorRequest::UdpBind {
machine_id,
local_address,
options,
} => todo!(),
ServerProcessorRequest::Send {
machine_id,
socket_id,
data,
} => todo!(),
ServerProcessorRequest::SendTo {
machine_id,
socket_id,
remote_address,
data,
} => todo!(),
ServerProcessorRequest::Recv {
machine_id,
socket_id,
len,
} => todo!(),
ServerProcessorRequest::RecvFrom {
machine_id,
socket_id,
len,
} => todo!(),
ServerProcessorRequest::GetRoutedLocalAddress {
machine_id,
address_type,
} => todo!(),
ServerProcessorRequest::FindGateway { machine_id } => todo!(),
ServerProcessorRequest::GetExternalAddress { gateway_id } => todo!(),
ServerProcessorRequest::AddPort {
gateway_id,
protocol,
external_port,
local_address,
lease_duration_ms,
description,
} => todo!(),
ServerProcessorRequest::RemovePort {
gateway_id,
protocol,
external_port,
} => todo!(),
}
}
}
impl Default for RouterServer {