mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
More topology stuff for VL2.
This commit is contained in:
parent
c05039f30d
commit
86ffb2861b
5 changed files with 170 additions and 9 deletions
|
@ -1,3 +1,61 @@
|
|||
pub struct Member {}
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub struct Topology {}
|
||||
use zerotier_utils::blob::Blob;
|
||||
use zerotier_utils::flatsortedmap::FlatSortedMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::vl1::identity::IDENTITY_FINGERPRINT_SIZE;
|
||||
use crate::vl1::inetaddress::InetAddress;
|
||||
use crate::vl2::rule::Rule;
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
|
||||
pub struct Member<'a> {
|
||||
#[serde(skip_serializing_if = "u64_zero")]
|
||||
#[serde(default)]
|
||||
pub flags: u64,
|
||||
|
||||
#[serde(skip_serializing_if = "cow_str_is_empty")]
|
||||
#[serde(default)]
|
||||
pub name: Cow<'a, str>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
|
||||
pub struct Topology<'a> {
|
||||
pub timestamp: i64,
|
||||
|
||||
#[serde(skip_serializing_if = "cow_str_is_empty")]
|
||||
#[serde(default)]
|
||||
pub name: Cow<'a, str>,
|
||||
|
||||
#[serde(skip_serializing_if = "slice_is_empty")]
|
||||
#[serde(default)]
|
||||
pub rules: Cow<'a, [Rule]>,
|
||||
|
||||
#[serde(skip_serializing_if = "FlatSortedMap::is_empty")]
|
||||
#[serde(default)]
|
||||
pub dns_resolvers: FlatSortedMap<'a, Cow<'a, str>, InetAddress>,
|
||||
|
||||
#[serde(skip_serializing_if = "FlatSortedMap::is_empty")]
|
||||
#[serde(default)]
|
||||
pub dns_names: FlatSortedMap<'a, Cow<'a, str>, InetAddress>,
|
||||
|
||||
#[serde(skip_serializing_if = "FlatSortedMap::is_empty")]
|
||||
#[serde(default)]
|
||||
pub members: FlatSortedMap<'a, Blob<IDENTITY_FINGERPRINT_SIZE>, Member<'a>>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn u64_zero(i: &u64) -> bool {
|
||||
*i == 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cow_str_is_empty<'a>(s: &Cow<'a, str>) -> bool {
|
||||
s.is_empty()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn slice_is_empty<T, S: AsRef<[T]>>(x: &S) -> bool {
|
||||
x.as_ref().is_empty()
|
||||
}
|
||||
|
|
|
@ -31,11 +31,6 @@ pub struct NetworkConfig {
|
|||
#[serde(default)]
|
||||
pub name: String,
|
||||
|
||||
/// A human-readable message for members of this network (V2 only)
|
||||
#[serde(skip_serializing_if = "String::is_empty")]
|
||||
#[serde(default)]
|
||||
pub motd: String,
|
||||
|
||||
/// True if network has access control (the default)
|
||||
pub private: bool,
|
||||
|
||||
|
@ -95,7 +90,6 @@ impl NetworkConfig {
|
|||
network_id,
|
||||
issued_to,
|
||||
name: String::new(),
|
||||
motd: String::new(),
|
||||
private: true,
|
||||
timestamp: 0,
|
||||
mtu: 0,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
use serde::ser::SerializeTuple;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
@ -72,6 +73,27 @@ impl<const L: usize> ToString for Blob<L> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> PartialOrd for Blob<L> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Ord for Blob<L> {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Hash for Blob<L> {
|
||||
#[inline(always)]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<const L: usize> Debug for Blob<L> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -118,7 +140,7 @@ impl<'de, const L: usize> serde::de::Visitor<'de> for BlobVisitor<L> {
|
|||
|
||||
impl<'de, const L: usize> Deserialize<'de> for Blob<L> {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Blob<L>, D::Error>
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
|
|
86
utils/src/flatsortedmap.rs
Normal file
86
utils/src/flatsortedmap.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* (c) ZeroTier, Inc.
|
||||
* https://www.zerotier.com/
|
||||
*/
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::iter::{FromIterator, Iterator};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A simple flat sorted map backed by a vector and binary search.
|
||||
///
|
||||
/// This doesn't support gradual adding of keys or removal of keys, but only construction
|
||||
/// from an iterator of keys and values. It also implements Serialize and Deserialize and
|
||||
/// is mainly intended for memory and space efficient serializable lookup tables.
|
||||
///
|
||||
/// If the iterator supplies more than one key with different values, which of these is
|
||||
/// included is undefined.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct FlatSortedMap<'a, K: Eq + Ord + Clone, V: Clone>(Cow<'a, [(K, V)]>);
|
||||
|
||||
impl<'a, K: Eq + Ord + Clone, V: Clone> FromIterator<(K, V)> for FlatSortedMap<'a, K, V> {
|
||||
#[inline]
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
|
||||
let mut tmp = Vec::from_iter(iter);
|
||||
tmp.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
||||
tmp.dedup_by(|a, b| a.0.eq(&b.0));
|
||||
Self(Cow::Owned(tmp))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Ord + Clone, V: Clone> Default for FlatSortedMap<'a, K, V> {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self(Cow::Owned(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Ord + Clone, V: Clone> FlatSortedMap<'a, K, V> {
|
||||
#[inline]
|
||||
pub fn get(&self, k: &K) -> Option<&V> {
|
||||
if let Ok(idx) = self.0.binary_search_by(|a| a.0.cmp(k)) {
|
||||
Some(unsafe { &self.0.get_unchecked(idx).1 })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, k: &K) -> bool {
|
||||
self.0.binary_search_by(|a| a.0.cmp(k)).is_ok()
|
||||
}
|
||||
|
||||
/// Returns true if this map is valid, meaning that it contains only one of each key and is sorted.
|
||||
#[inline]
|
||||
pub fn is_valid(&self) -> bool {
|
||||
let l = self.0.len();
|
||||
if l > 1 {
|
||||
for i in 1..l {
|
||||
if unsafe { !self.0.get_unchecked(i - 1).0.cmp(&self.0.get_unchecked(i).0).is_lt() } {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn iter(&self) -> impl Iterator<Item = &(K, V)> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ pub mod dictionary;
|
|||
pub mod error;
|
||||
#[allow(unused)]
|
||||
pub mod exitcode;
|
||||
pub mod flatsortedmap;
|
||||
pub mod gate;
|
||||
pub mod gatherarray;
|
||||
pub mod hex;
|
||||
|
|
Loading…
Add table
Reference in a new issue