Browse Source

Add RPL Rank logic

Signed-off-by: Thibaut Vandervelden <[email protected]>
Thibaut Vandervelden 1 year ago
parent
commit
6513c941de
3 changed files with 105 additions and 0 deletions
  1. 2 0
      src/iface/rpl/consts.rs
  2. 1 0
      src/iface/rpl/mod.rs
  3. 102 0
      src/iface/rpl/rank.rs

+ 2 - 0
src/iface/rpl/consts.rs

@@ -1,5 +1,7 @@
 pub const SEQUENCE_WINDOW: u8 = 16;
 
+pub const DEFAULT_MIN_HOP_RANK_INCREASE: u16 = 256;
+
 pub const DEFAULT_DIO_INTERVAL_MIN: u32 = 12;
 pub const DEFAULT_DIO_REDUNDANCY_CONSTANT: usize = 10;
 /// This is 20 in the standard, but in Contiki they use:

+ 1 - 0
src/iface/rpl/mod.rs

@@ -2,4 +2,5 @@
 
 mod consts;
 mod lollipop;
+mod rank;
 mod trickle;

+ 102 - 0
src/iface/rpl/rank.rs

@@ -0,0 +1,102 @@
+//! Implementation of the Rank comparison in RPL.
+//!
+//! A Rank can be thought of as a fixed-point number, where the position of the radix point between
+//! the integer part and the fractional part is determined by `MinHopRankIncrease`.
+//! `MinHopRankIncrease` is the minimum increase in Rank between a node and any of its DODAG
+//! parents.
+//! This value is provisined by the DODAG root.
+//!
+//! When Rank is compared, the integer portion of the Rank is to be used.
+//!
+//! Meaning of the comparison:
+//! - **Rank M is less than Rank N**: the position of M is closer to the DODAG root than the position
+//! of N. Node M may safely be a DODAG parent for node N.
+//! - **Ranks are equal**: the positions of both nodes within the DODAG and with respect to the DODAG
+//! are similar or identical. Routing through a node with equal Rank may cause a routing loop.
+//! - **Rank M is greater than Rank N**: the position of node M is farther from the DODAG root
+//! than the position of N. Node M may in fact be in the sub-DODAG of node N. If node N selects
+//! node M as a DODAG parent, there is a risk of creating a loop.
+
+use super::consts::DEFAULT_MIN_HOP_RANK_INCREASE;
+
+/// The Rank is the expression of the relative position within a DODAG Version with regard to
+/// neighbors, and it is not necessarily a good indication or a proper expression of a distance or
+/// a path cost to the root.
+#[derive(Debug, Clone, Copy, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Rank {
+    value: u16,
+    min_hop_rank_increase: u16,
+}
+
+impl core::fmt::Display for Rank {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "Rank({})", self.dag_rank())
+    }
+}
+
+impl Rank {
+    pub const INFINITE: Self = Rank::new(0xffff, DEFAULT_MIN_HOP_RANK_INCREASE);
+
+    /// The ROOT_RANK is the smallest rank possible.
+    /// DAG_RANK(ROOT_RANK) should be 1. See RFC6550 § 17.
+    pub const ROOT: Self = Rank::new(DEFAULT_MIN_HOP_RANK_INCREASE, DEFAULT_MIN_HOP_RANK_INCREASE);
+
+    /// Create a new Rank from some value and a `MinHopRankIncrease`.
+    /// The `MinHopRankIncrease` is used for calculating the integer part for comparing to other
+    /// Ranks.
+    pub const fn new(value: u16, min_hop_rank_increase: u16) -> Self {
+        Self {
+            value,
+            min_hop_rank_increase,
+        }
+    }
+
+    /// Return the integer part of the Rank.
+    pub fn dag_rank(&self) -> u16 {
+        self.value / self.min_hop_rank_increase
+    }
+
+    /// Return the raw Rank value.
+    pub fn raw_value(&self) -> u16 {
+        self.value
+    }
+}
+
+impl PartialEq for Rank {
+    fn eq(&self, other: &Self) -> bool {
+        self.dag_rank() == other.dag_rank()
+    }
+}
+
+impl PartialOrd for Rank {
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        self.dag_rank().partial_cmp(&other.dag_rank())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn calculate_rank() {
+        let r = Rank::new(27, 16);
+        assert_eq!(r.dag_rank(), 1)
+    }
+
+    #[test]
+    fn comparison() {
+        let r1 = Rank::ROOT;
+        let r2 = Rank::new(16, 16);
+        assert!(r1 == r2);
+
+        let r1 = Rank::new(16, 16);
+        let r2 = Rank::new(32, 16);
+        assert!(r1 < r2);
+
+        let r1 = Rank::ROOT;
+        let r2 = Rank::INFINITE;
+        assert!(r1 < r2);
+    }
+}