From 2fcc9e63c63f47eea909a4aba70b586d9309d78d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Sat, 31 Dec 2022 16:03:02 -0500 Subject: [PATCH] Some renaming and generic simplification. --- controller/src/controller.rs | 8 +-- controller/src/main.rs | 4 +- network-hypervisor/src/vl1/mod.rs | 2 +- network-hypervisor/src/vl1/node.rs | 79 ++++++++++++------------- network-hypervisor/src/vl1/peer.rs | 18 +++--- network-hypervisor/src/vl2/switch.rs | 4 +- vl1-service/src/vl1service.rs | 86 ++++++---------------------- 7 files changed, 72 insertions(+), 129 deletions(-) diff --git a/controller/src/controller.rs b/controller/src/controller.rs index 17fed8abb..679be5b39 100644 --- a/controller/src/controller.rs +++ b/controller/src/controller.rs @@ -31,7 +31,7 @@ const REQUEST_TIMEOUT: Duration = Duration::from_secs(10); /// ZeroTier VL2 network controller packet handler, answers VL2 netconf queries. pub struct Controller { self_ref: Weak, - service: RwLock>>, + service: RwLock>>, reaper: Reaper, runtime: tokio::runtime::Handle, database: Arc, @@ -78,7 +78,7 @@ impl Controller { /// This must be called once the service that uses this handler is up or the controller /// won't actually do anything. The controller holds a weak reference to VL1Service so /// be sure it's not dropped. - pub async fn start(&self, service: &Arc>) { + pub async fn start(&self, service: &Arc>) { *self.service.write().unwrap() = Arc::downgrade(service); // Create database change listener. @@ -497,7 +497,7 @@ impl Controller { } } -impl InnerProtocol for Controller { +impl InnerProtocolLayer for Controller { fn handle_packet( &self, host_system: &HostSystemImpl, @@ -512,7 +512,7 @@ impl InnerProtocol for Controller { ) -> PacketHandlerResult { match verb { protocol::message_type::VL2_NETWORK_CONFIG_REQUEST => { - if !host_system.should_respond_to(&source.identity) { + if !host_system.peer_filter().should_respond_to(&source.identity) { return PacketHandlerResult::Ok; // handled and ignored } diff --git a/controller/src/main.rs b/controller/src/main.rs index 624b0bd19..c2d5c53c1 100644 --- a/controller/src/main.rs +++ b/controller/src/main.rs @@ -13,7 +13,7 @@ use zerotier_utils::exitcode; use zerotier_utils::tokio::runtime::Runtime; use zerotier_vl1_service::VL1Service; -async fn run(database: Arc, runtime: &Runtime) -> i32 { +async fn run(database: Arc, runtime: &Runtime) -> i32 { let handler = Controller::new(database.clone(), runtime.handle().clone()).await; if handler.is_err() { eprintln!("FATAL: error initializing handler: {}", handler.err().unwrap().to_string()); @@ -22,7 +22,7 @@ async fn run(database: Arc, runtime: &Runtime) -> i32 { let handler = handler.unwrap(); let svc = VL1Service::new( - database.clone(), + database, handler.clone(), handler.clone(), zerotier_vl1_service::VL1Settings::default(), diff --git a/network-hypervisor/src/vl1/mod.rs b/network-hypervisor/src/vl1/mod.rs index 8bab15241..a1527e57d 100644 --- a/network-hypervisor/src/vl1/mod.rs +++ b/network-hypervisor/src/vl1/mod.rs @@ -18,7 +18,7 @@ pub use event::Event; pub use identity::Identity; pub use inetaddress::InetAddress; pub use mac::MAC; -pub use node::{ApplicationLayer, DummyInnerLayer, InnerLayer, Node, NodeStorageProvider, PacketHandlerResult, PeerFilter}; +pub use node::{ApplicationLayer, DummyInnerLayer, InnerProtocolLayer, Node, NodeStorageProvider, PacketHandlerResult, PeerFilter}; pub use path::Path; pub use peer::Peer; pub use rootset::{Root, RootSet}; diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs index 1cbf4227f..daddbbcaa 100644 --- a/network-hypervisor/src/vl1/node.rs +++ b/network-hypervisor/src/vl1/node.rs @@ -27,42 +27,11 @@ use zerotier_utils::marshalable::Marshalable; use zerotier_utils::ringbuffer::RingBuffer; use zerotier_utils::thing::Thing; -/// Trait providing functions to determine what peers we should talk to. +/// Interface trait to be implemented by code that's using the ZeroTier network hypervisor. /// -/// This is included in ApplicationLayer but is provided as a separate trait to make it easy for -/// implementers of ApplicationLayer to break this out and allow a user to specify it. -pub trait PeerFilter: Sync + Send { - /// Check if this node should respond to messages from a given peer at all. - /// - /// If this returns false, the node simply drops messages on the floor and refuses - /// to init V2 sessions. - fn should_respond_to(&self, id: &Verified) -> bool; - - /// Check if this node has any trust relationship with the provided identity. - /// - /// This should return true if there is any special trust relationship such as mutual - /// membership in a network or for controllers the peer's membership in any network - /// they control. - fn has_trust_relationship(&self, id: &Verified) -> bool; -} - -/// Trait to be implemented by outside code to provide object storage to VL1 -/// -/// This is included in ApplicationLayer but is provided as a separate trait to make it easy for -/// implementers of ApplicationLayer to break this out and allow a user to specify it. -pub trait NodeStorageProvider: Sync + Send { - /// Load this node's identity from the data store. - fn load_node_identity(&self) -> Option>; - - /// Save this node's identity to the data store. - fn save_node_identity(&self, id: &Verified); -} - -/// Trait implemented by external code to handle events and provide an interface to the system or application. -pub trait ApplicationLayer: PeerFilter + NodeStorageProvider + 'static { - /// Type for implementation of NodeStorage. - type Storage: NodeStorageProvider + ?Sized; - +/// This is analogous to a C struct full of function pointers to callbacks along with some +/// associated type definitions. +pub trait ApplicationLayer: 'static { /// Type for local system sockets. type LocalSocket: Sync + Send + Hash + PartialEq + Eq + Clone + ToString + Sized + 'static; @@ -73,7 +42,10 @@ pub trait ApplicationLayer: PeerFilter + NodeStorageProvider + 'static { fn event(&self, event: Event); /// Get a reference to the local storage implementation at this host. - fn storage(&self) -> &Self::Storage; + fn storage(&self) -> &dyn NodeStorageProvider; + + /// Get the PeerFilter implementation used to check whether this node should communicate at VL1 with other peers. + fn peer_filter(&self) -> &dyn PeerFilter; /// Get a pooled packet buffer for internal use. fn get_buffer(&self) -> PooledPacketBuffer; @@ -140,6 +112,31 @@ pub trait ApplicationLayer: PeerFilter + NodeStorageProvider + 'static { fn time_clock(&self) -> i64; } +/// Trait providing functions to determine what peers we should talk to. +pub trait PeerFilter: Sync + Send { + /// Check if this node should respond to messages from a given peer at all. + /// + /// If this returns false, the node simply drops messages on the floor and refuses + /// to init V2 sessions. + fn should_respond_to(&self, id: &Verified) -> bool; + + /// Check if this node has any trust relationship with the provided identity. + /// + /// This should return true if there is any special trust relationship such as mutual + /// membership in a network or for controllers the peer's membership in any network + /// they control. + fn has_trust_relationship(&self, id: &Verified) -> bool; +} + +/// Trait to be implemented by outside code to provide object storage to VL1 +pub trait NodeStorageProvider: Sync + Send { + /// Load this node's identity from the data store. + fn load_node_identity(&self) -> Option>; + + /// Save this node's identity to the data store. + fn save_node_identity(&self, id: &Verified); +} + /// Result of a packet handler. pub enum PacketHandlerResult { /// Packet was handled successfully. @@ -157,7 +154,7 @@ pub enum PacketHandlerResult { /// This is implemented by Switch in VL2. It's usually not used outside of VL2 in the core but /// it could also be implemented for testing or "off label" use of VL1 to carry different protocols. #[allow(unused)] -pub trait InnerLayer: Sync + Send { +pub trait InnerProtocolLayer: Sync + Send { /// Handle a packet, returning true if it was handled by the next layer. /// /// Do not attempt to handle OK or ERROR. Instead implement handle_ok() and handle_error(). @@ -729,7 +726,7 @@ impl Node { INTERVAL } - pub fn handle_incoming_physical_packet( + pub fn handle_incoming_physical_packet( &self, app: &Application, inner: &Inner, @@ -972,7 +969,7 @@ impl Node { } /// Called by Peer when an identity is received from another node, e.g. via OK(WHOIS). - pub(crate) fn handle_incoming_identity( + pub(crate) fn handle_incoming_identity( &self, app: &Application, inner: &Inner, @@ -985,7 +982,7 @@ impl Node { let mut whois_queue = self.whois_queue.lock().unwrap(); if let Some(qi) = whois_queue.get_mut(&received_identity.address) { let address = received_identity.address; - if app.should_respond_to(&received_identity) { + if app.peer_filter().should_respond_to(&received_identity) { let mut peers = self.peers.write().unwrap(); if let Some(peer) = peers.get(&address).cloned().or_else(|| { Peer::new(&self.identity, received_identity, time_ticks) @@ -1110,7 +1107,7 @@ impl PathKey<'_, '_, Application> { #[derive(Default)] pub struct DummyInnerLayer; -impl InnerLayer for DummyInnerLayer {} +impl InnerProtocolLayer for DummyInnerLayer {} impl PeerFilter for DummyInnerLayer { #[inline(always)] diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs index 697af63d7..fd09965f2 100644 --- a/network-hypervisor/src/vl1/peer.rs +++ b/network-hypervisor/src/vl1/peer.rs @@ -478,7 +478,7 @@ impl Peer { /// those fragments after the main packet header and first chunk. /// /// This returns true if the packet decrypted and passed authentication. - pub(crate) fn v1_proto_receive( + pub(crate) fn v1_proto_receive( self: &Arc, node: &Node, app: &Application, @@ -583,7 +583,7 @@ impl Peer { return PacketHandlerResult::Error; } - fn handle_incoming_hello( + fn handle_incoming_hello( &self, app: &Application, inner: &Inner, @@ -593,7 +593,7 @@ impl Peer { source_path: &Arc, payload: &PacketBuffer, ) -> PacketHandlerResult { - if !(app.should_respond_to(&self.identity) || node.this_node_is_root() || node.is_peer_root(self)) { + if !(app.peer_filter().should_respond_to(&self.identity) || node.this_node_is_root() || node.is_peer_root(self)) { debug_event!( app, "[vl1] dropping HELLO from {} due to lack of trust relationship", @@ -638,7 +638,7 @@ impl Peer { return PacketHandlerResult::Error; } - fn handle_incoming_error( + fn handle_incoming_error( self: &Arc, app: &Application, inner: &Inner, @@ -676,7 +676,7 @@ impl Peer { return PacketHandlerResult::Error; } - fn handle_incoming_ok( + fn handle_incoming_ok( self: &Arc, app: &Application, inner: &Inner, @@ -778,7 +778,7 @@ impl Peer { return PacketHandlerResult::Error; } - fn handle_incoming_whois( + fn handle_incoming_whois( self: &Arc, app: &Application, inner: &Inner, @@ -787,7 +787,7 @@ impl Peer { message_id: MessageId, payload: &PacketBuffer, ) -> PacketHandlerResult { - if node.this_node_is_root() || app.should_respond_to(&self.identity) { + if node.this_node_is_root() || app.peer_filter().should_respond_to(&self.identity) { let mut addresses = payload.as_bytes(); while addresses.len() >= ADDRESS_SIZE { if !self @@ -824,7 +824,7 @@ impl Peer { return PacketHandlerResult::Ok; } - fn handle_incoming_echo( + fn handle_incoming_echo( &self, app: &Application, inner: &Inner, @@ -833,7 +833,7 @@ impl Peer { message_id: MessageId, payload: &PacketBuffer, ) -> PacketHandlerResult { - if app.should_respond_to(&self.identity) || node.is_peer_root(self) { + if app.peer_filter().should_respond_to(&self.identity) || node.is_peer_root(self) { self.send(app, node, None, time_ticks, |packet| { let mut f: &mut OkHeader = packet.append_struct_get_mut().unwrap(); f.verb = message_type::VL1_OK; diff --git a/network-hypervisor/src/vl2/switch.rs b/network-hypervisor/src/vl2/switch.rs index 8dde12e2b..3e2a3f32f 100644 --- a/network-hypervisor/src/vl2/switch.rs +++ b/network-hypervisor/src/vl2/switch.rs @@ -3,14 +3,14 @@ use std::sync::Arc; use crate::protocol::PacketBuffer; -use crate::vl1::{ApplicationLayer, InnerLayer, Node, PacketHandlerResult, Path, Peer}; +use crate::vl1::{ApplicationLayer, InnerProtocolLayer, Node, PacketHandlerResult, Path, Peer}; pub trait SwitchInterface: Sync + Send {} pub struct Switch {} #[allow(unused_variables)] -impl InnerLayer for Switch { +impl InnerProtocolLayer for Switch { fn handle_packet( &self, app: &Application, diff --git a/vl1-service/src/vl1service.rs b/vl1-service/src/vl1service.rs index 548a47cac..811dcee05 100644 --- a/vl1-service/src/vl1service.rs +++ b/vl1-service/src/vl1service.rs @@ -26,14 +26,10 @@ const UPDATE_UDP_BINDINGS_EVERY_SECS: usize = 10; /// talks to the physical network, manages the vl1 node, and presents a templated interface for /// whatever inner protocol implementation is using it. This would typically be VL2 but could be /// a test harness or just the controller for a controller that runs stand-alone. -pub struct VL1Service< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, -> { +pub struct VL1Service { state: RwLock, - storage: Arc, - vl1_auth_provider: Arc, + storage: Arc, + peer_filter: Arc, inner: Arc, buffer_pool: Arc, node_container: Option, // never None, set in new() @@ -46,15 +42,10 @@ struct VL1ServiceMutableState { running: bool, } -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > VL1Service -{ +impl VL1Service { pub fn new( - storage: Arc, - vl1_auth_provider: Arc, + storage: Arc, + peer_filter: Arc, inner: Arc, settings: VL1Settings, ) -> Result, Box> { @@ -66,7 +57,7 @@ impl< running: true, }), storage, - vl1_auth_provider, + peer_filter, inner, buffer_pool: Arc::new(PacketBufferPool::new( std::thread::available_parallelism().map_or(2, |c| c.get() + 2), @@ -189,12 +180,7 @@ impl< } } -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > UdpPacketHandler for VL1Service -{ +impl UdpPacketHandler for VL1Service { #[inline(always)] fn incoming_udp_packet( self: &Arc, @@ -215,13 +201,7 @@ impl< } } -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > ApplicationLayer for VL1Service -{ - type Storage = NodeStorageImpl; +impl ApplicationLayer for VL1Service { type LocalSocket = crate::LocalSocket; type LocalInterface = crate::LocalInterface; @@ -238,10 +218,15 @@ impl< } #[inline(always)] - fn storage(&self) -> &Self::Storage { + fn storage(&self) -> &dyn NodeStorageProvider { self.storage.as_ref() } + #[inline(always)] + fn peer_filter(&self) -> &dyn PeerFilter { + self.peer_filter.as_ref() + } + #[inline] fn get_buffer(&self) -> zerotier_network_hypervisor::protocol::PooledPacketBuffer { self.buffer_pool.get() @@ -321,46 +306,7 @@ impl< } } -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > NodeStorageProvider for VL1Service -{ - #[inline(always)] - fn load_node_identity(&self) -> Option> { - self.storage.load_node_identity() - } - - #[inline(always)] - fn save_node_identity(&self, id: &Verified) { - self.storage.save_node_identity(id) - } -} - -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > PeerFilter for VL1Service -{ - #[inline(always)] - fn should_respond_to(&self, id: &Verified) -> bool { - self.vl1_auth_provider.should_respond_to(id) - } - - #[inline(always)] - fn has_trust_relationship(&self, id: &Verified) -> bool { - self.vl1_auth_provider.has_trust_relationship(id) - } -} - -impl< - NodeStorageImpl: NodeStorageProvider + ?Sized + 'static, - PeerToPeerAuthentication: PeerFilter + ?Sized + 'static, - Inner: InnerLayer + ?Sized + 'static, - > Drop for VL1Service -{ +impl Drop for VL1Service { fn drop(&mut self) { let mut state = self.state.write().unwrap(); state.running = false;