atm0s_sdn_router/
lib.rs

1#![allow(clippy::bool_assert_comparison)]
2
3use atm0s_sdn_identity::{NodeId, NodeIdType};
4pub mod core;
5pub mod shadow;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum ServiceBroadcastLevel {
9    Global,
10    Geo1,
11    Geo2,
12    Group,
13}
14
15impl ServiceBroadcastLevel {
16    pub fn same_level(&self, node1: NodeId, node2: NodeId) -> bool {
17        match self {
18            ServiceBroadcastLevel::Global => true,
19            ServiceBroadcastLevel::Geo1 => node1.geo1() == node2.geo1(),
20            ServiceBroadcastLevel::Geo2 => node1.geo1() == node2.geo1() && node1.geo2() == node2.geo2(),
21            ServiceBroadcastLevel::Group => node1.geo1() == node2.geo1() && node1.geo2() == node2.geo2() && node1.group() == node2.group(),
22        }
23    }
24}
25
26impl From<ServiceBroadcastLevel> for u8 {
27    fn from(val: ServiceBroadcastLevel) -> Self {
28        match val {
29            ServiceBroadcastLevel::Global => 0,
30            ServiceBroadcastLevel::Geo1 => 1,
31            ServiceBroadcastLevel::Geo2 => 2,
32            ServiceBroadcastLevel::Group => 3,
33        }
34    }
35}
36
37impl From<u8> for ServiceBroadcastLevel {
38    fn from(val: u8) -> Self {
39        match val {
40            0 => ServiceBroadcastLevel::Global,
41            1 => ServiceBroadcastLevel::Geo1,
42            2 => ServiceBroadcastLevel::Geo2,
43            _ => ServiceBroadcastLevel::Group,
44        }
45    }
46}
47
48#[derive(Clone, Debug, Eq, PartialEq)]
49pub enum RouteRule {
50    Direct,
51    ToNode(NodeId),
52    ToService(u8),
53    /// First is service id, second is the level, and third is seq of message
54    ToServices(u8, ServiceBroadcastLevel, u16),
55    ToKey(NodeId),
56}
57
58/// Determine the destination of an action/message
59#[derive(Clone, Debug, Eq, PartialEq)]
60pub enum RouteAction<Remote> {
61    /// Reject the message
62    Reject,
63    /// Will be processed locally
64    Local,
65    /// Will be forward to the given connection
66    Next(Remote),
67    /// Will be forward to the given connection, first is local or not, next is the list of remote dests
68    Broadcast(bool, Vec<Remote>),
69}
70
71impl<Remote> RouteAction<Remote> {
72    pub fn is_local(&self) -> bool {
73        matches!(self, RouteAction::Local)
74    }
75
76    pub fn is_reject(&self) -> bool {
77        matches!(self, RouteAction::Reject)
78    }
79
80    pub fn is_remote(&self) -> bool {
81        matches!(self, RouteAction::Next(_))
82    }
83}
84
85pub trait RouterTable<Remote> {
86    /// Find the closest node for the given key
87    fn closest_for(&self, key: NodeId) -> Option<Remote>;
88    /// Find the next node for the given destination node
89    fn next(&self, dest: NodeId) -> Option<Remote>;
90    /// Determine the next action for the given destination node
91    fn path_to_node(&self, dest: NodeId) -> RouteAction<Remote>;
92    /// Determine the next action for the given key
93    fn path_to_key(&self, key: NodeId) -> RouteAction<Remote>;
94    /// Determine the next action for the given service
95    fn path_to_service(&self, service_id: u8) -> RouteAction<Remote>;
96    /// Determine the next action if we need broadcast to all node running a service.
97    /// If relay_from is set, it should not sending back for avoiding loop
98    fn path_to_services(&self, service_id: u8, seq: u16, level: ServiceBroadcastLevel, source: Option<NodeId>, relay_from: Option<NodeId>) -> RouteAction<Remote>;
99    /// Determine next action for incoming messages
100    /// given the route rule and service id
101    fn derive_action(&self, route: &RouteRule, source: Option<NodeId>, relay_from: Option<NodeId>) -> RouteAction<Remote> {
102        match route {
103            RouteRule::Direct => RouteAction::Local,
104            RouteRule::ToNode(dest) => self.path_to_node(*dest),
105            RouteRule::ToKey(key) => self.path_to_key(*key),
106            RouteRule::ToService(service) => self.path_to_service(*service),
107            RouteRule::ToServices(service, level, seq) => self.path_to_services(*service, *seq, *level, source, relay_from),
108        }
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use atm0s_sdn_identity::ConnId;
115    type RouteAction = super::RouteAction<ConnId>;
116
117    #[test]
118    fn test_is_local() {
119        let local = RouteAction::Local;
120        let remote = RouteAction::Next(ConnId::from_in(1, 1));
121        let reject = RouteAction::Reject;
122
123        assert!(local.is_local());
124        assert!(!remote.is_local());
125        assert!(!reject.is_local());
126    }
127
128    #[test]
129    fn test_is_reject() {
130        let local = RouteAction::Local;
131        let remote = RouteAction::Next(ConnId::from_in(1, 1));
132        let reject = RouteAction::Reject;
133
134        assert!(!local.is_reject());
135        assert!(!remote.is_reject());
136        assert!(reject.is_reject());
137    }
138
139    #[test]
140    fn test_is_remote() {
141        let local = RouteAction::Local;
142        let remote = RouteAction::Next(ConnId::from_in(1, 1));
143        let reject = RouteAction::Reject;
144
145        assert!(!local.is_remote());
146        assert!(remote.is_remote());
147        assert!(!reject.is_remote());
148    }
149}