Some renaming and generic simplification.

This commit is contained in:
Adam Ierymenko 2022-12-31 16:03:02 -05:00
parent 30d58bee76
commit 2fcc9e63c6
7 changed files with 72 additions and 129 deletions

View file

@ -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<Self>,
service: RwLock<Weak<VL1Service<dyn Database, Self, Self>>>,
service: RwLock<Weak<VL1Service<Self>>>,
reaper: Reaper,
runtime: tokio::runtime::Handle,
database: Arc<dyn Database>,
@ -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<VL1Service<dyn Database, Self, Self>>) {
pub async fn start(&self, service: &Arc<VL1Service<Self>>) {
*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<HostSystemImpl: ApplicationLayer + ?Sized>(
&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
}

View file

@ -13,7 +13,7 @@ use zerotier_utils::exitcode;
use zerotier_utils::tokio::runtime::Runtime;
use zerotier_vl1_service::VL1Service;
async fn run(database: Arc<dyn Database>, runtime: &Runtime) -> i32 {
async fn run(database: Arc<impl Database>, 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<dyn Database>, runtime: &Runtime) -> i32 {
let handler = handler.unwrap();
let svc = VL1Service::new(
database.clone(),
database,
handler.clone(),
handler.clone(),
zerotier_vl1_service::VL1Settings::default(),

View file

@ -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};

View file

@ -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<Identity>) -> 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<Identity>) -> 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<Verified<Identity>>;
/// Save this node's identity to the data store.
fn save_node_identity(&self, id: &Verified<Identity>);
}
/// 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<Identity>) -> 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<Identity>) -> 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<Verified<Identity>>;
/// Save this node's identity to the data store.
fn save_node_identity(&self, id: &Verified<Identity>);
}
/// 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<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
pub fn handle_incoming_physical_packet<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
&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<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
pub(crate) fn handle_incoming_identity<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
&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<Application: ApplicationLayer + ?Sized> PathKey<'_, '_, Application> {
#[derive(Default)]
pub struct DummyInnerLayer;
impl InnerLayer for DummyInnerLayer {}
impl InnerProtocolLayer for DummyInnerLayer {}
impl PeerFilter for DummyInnerLayer {
#[inline(always)]

View file

@ -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<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
pub(crate) fn v1_proto_receive<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
self: &Arc<Self>,
node: &Node,
app: &Application,
@ -583,7 +583,7 @@ impl Peer {
return PacketHandlerResult::Error;
}
fn handle_incoming_hello<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
fn handle_incoming_hello<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
&self,
app: &Application,
inner: &Inner,
@ -593,7 +593,7 @@ impl Peer {
source_path: &Arc<Path>,
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<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
fn handle_incoming_error<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
self: &Arc<Self>,
app: &Application,
inner: &Inner,
@ -676,7 +676,7 @@ impl Peer {
return PacketHandlerResult::Error;
}
fn handle_incoming_ok<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
fn handle_incoming_ok<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
self: &Arc<Self>,
app: &Application,
inner: &Inner,
@ -778,7 +778,7 @@ impl Peer {
return PacketHandlerResult::Error;
}
fn handle_incoming_whois<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
fn handle_incoming_whois<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
self: &Arc<Self>,
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<Application: ApplicationLayer + ?Sized, Inner: InnerLayer + ?Sized>(
fn handle_incoming_echo<Application: ApplicationLayer + ?Sized, Inner: InnerProtocolLayer + ?Sized>(
&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;

View file

@ -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<Application: ApplicationLayer + ?Sized>(
&self,
app: &Application,

View file

@ -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<Inner: InnerProtocolLayer + ?Sized + 'static> {
state: RwLock<VL1ServiceMutableState>,
storage: Arc<NodeStorageImpl>,
vl1_auth_provider: Arc<PeerToPeerAuthentication>,
storage: Arc<dyn NodeStorageProvider>,
peer_filter: Arc<dyn PeerFilter>,
inner: Arc<Inner>,
buffer_pool: Arc<PacketBufferPool>,
node_container: Option<Node>, // 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<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
impl<Inner: InnerProtocolLayer + ?Sized + 'static> VL1Service<Inner> {
pub fn new(
storage: Arc<NodeStorageImpl>,
vl1_auth_provider: Arc<PeerToPeerAuthentication>,
storage: Arc<dyn NodeStorageProvider>,
peer_filter: Arc<dyn PeerFilter>,
inner: Arc<Inner>,
settings: VL1Settings,
) -> Result<Arc<Self>, Box<dyn Error>> {
@ -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<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
impl<Inner: InnerProtocolLayer + ?Sized + 'static> UdpPacketHandler for VL1Service<Inner> {
#[inline(always)]
fn incoming_udp_packet(
self: &Arc<Self>,
@ -215,13 +201,7 @@ impl<
}
}
impl<
NodeStorageImpl: NodeStorageProvider + ?Sized + 'static,
PeerToPeerAuthentication: PeerFilter + ?Sized + 'static,
Inner: InnerLayer + ?Sized + 'static,
> ApplicationLayer for VL1Service<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
type Storage = NodeStorageImpl;
impl<Inner: InnerProtocolLayer + ?Sized + 'static> ApplicationLayer for VL1Service<Inner> {
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<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
#[inline(always)]
fn load_node_identity(&self) -> Option<Verified<Identity>> {
self.storage.load_node_identity()
}
#[inline(always)]
fn save_node_identity(&self, id: &Verified<Identity>) {
self.storage.save_node_identity(id)
}
}
impl<
NodeStorageImpl: NodeStorageProvider + ?Sized + 'static,
PeerToPeerAuthentication: PeerFilter + ?Sized + 'static,
Inner: InnerLayer + ?Sized + 'static,
> PeerFilter for VL1Service<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
#[inline(always)]
fn should_respond_to(&self, id: &Verified<Identity>) -> bool {
self.vl1_auth_provider.should_respond_to(id)
}
#[inline(always)]
fn has_trust_relationship(&self, id: &Verified<Identity>) -> 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<NodeStorageImpl, PeerToPeerAuthentication, Inner>
{
impl<Inner: InnerProtocolLayer + ?Sized + 'static> Drop for VL1Service<Inner> {
fn drop(&mut self) {
let mut state = self.state.write().unwrap();
state.running = false;