From f68603d8b8915a1fb26a34f9236cf34d5d6fbef9 Mon Sep 17 00:00:00 2001 From: Thibaut Vandervelden Date: Mon, 5 Jun 2023 13:03:44 +0200 Subject: [PATCH] Add objective function and parent set --- Cargo.toml | 6 ++ build.rs | 1 + gen_config.py | 1 + src/iface/rpl/mod.rs | 2 + src/iface/rpl/of0.rs | 131 +++++++++++++++++++++++++++ src/iface/rpl/parents.rs | 189 +++++++++++++++++++++++++++++++++++++++ src/iface/rpl/rank.rs | 6 +- src/lib.rs | 1 + 8 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 src/iface/rpl/of0.rs create mode 100644 src/iface/rpl/parents.rs diff --git a/Cargo.toml b/Cargo.toml index 280ba7d0..f9a4b8a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -223,6 +223,12 @@ rpl-relations-buffer-count-32 = [] rpl-relations-buffer-count-64 = [] rpl-relations-buffer-count-128 = [] +rpl-parents-buffer-count-2 = [] +rpl-parents-buffer-count-4 = [] +rpl-parents-buffer-count-8 = [] # Default +rpl-parents-buffer-count-16 = [] +rpl-parents-buffer-count-32 = [] + # END AUTOGENERATED CONFIG FEATURES [[example]] diff --git a/build.rs b/build.rs index 19dd8636..56871392 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ static CONFIGS: &[(&str, usize)] = &[ ("DNS_MAX_SERVER_COUNT", 1), ("DNS_MAX_NAME_SIZE", 255), ("RPL_RELATIONS_BUFFER_COUNT", 16), + ("RPL_PARENTS_BUFFER_COUNT", 8), // END AUTOGENERATED CONFIG FEATURES ]; diff --git a/gen_config.py b/gen_config.py index 46549b70..5d327a6d 100644 --- a/gen_config.py +++ b/gen_config.py @@ -40,6 +40,7 @@ feature("dns_max_result_count", default=1, min=1, max=32, pow2=4) feature("dns_max_server_count", default=1, min=1, max=32, pow2=4) feature("dns_max_name_size", default=255, min=64, max=255, pow2=True) feature("rpl_relations_buffer_count", default=16, min=1, max=128, pow2=True) +feature("rpl_parents_buffer_count", default=8, min=2, max=32, pow2=True) # ========= Update Cargo.toml diff --git a/src/iface/rpl/mod.rs b/src/iface/rpl/mod.rs index d7da7aa1..69aa9ae7 100644 --- a/src/iface/rpl/mod.rs +++ b/src/iface/rpl/mod.rs @@ -2,6 +2,8 @@ mod consts; mod lollipop; +mod of0; +mod parents; mod rank; mod relations; mod trickle; diff --git a/src/iface/rpl/of0.rs b/src/iface/rpl/of0.rs new file mode 100644 index 00000000..4a771431 --- /dev/null +++ b/src/iface/rpl/of0.rs @@ -0,0 +1,131 @@ +use super::parents::*; +use super::rank::Rank; + +pub struct ObjectiveFunction0; + +pub(crate) trait ObjectiveFunction { + const OCP: u16; + + /// Return the new calculated Rank, based on information from the parent. + fn rank(current_rank: Rank, parent_rank: Rank) -> Rank; + + /// Return the preferred parent from a given parent set. + fn preferred_parent(parent_set: &ParentSet) -> Option<&Parent>; +} + +impl ObjectiveFunction0 { + const OCP: u16 = 0; + + const RANK_STRETCH: u16 = 0; + const RANK_FACTOR: u16 = 1; + const RANK_STEP: u16 = 3; + + fn rank_increase(parent_rank: Rank) -> u16 { + (Self::RANK_FACTOR * Self::RANK_STEP + Self::RANK_STRETCH) + * parent_rank.min_hop_rank_increase + } +} + +impl ObjectiveFunction for ObjectiveFunction0 { + const OCP: u16 = 0; + + fn rank(_: Rank, parent_rank: Rank) -> Rank { + assert_ne!(parent_rank, Rank::INFINITE); + + Rank::new( + parent_rank.value + Self::rank_increase(parent_rank), + parent_rank.min_hop_rank_increase, + ) + } + + fn preferred_parent(parent_set: &ParentSet) -> Option<&Parent> { + let mut pref_parent: Option<&Parent> = None; + + for parent in parent_set.parents() { + if pref_parent.is_none() || parent.rank() < pref_parent.unwrap().rank() { + pref_parent = Some(parent); + } + } + + pref_parent + } +} + +#[cfg(test)] +mod tests { + use crate::iface::rpl::consts::DEFAULT_MIN_HOP_RANK_INCREASE; + + use super::*; + + #[test] + fn rank_increase() { + // 256 (root) + 3 * 256 + assert_eq!( + ObjectiveFunction0::rank(Rank::INFINITE, Rank::ROOT), + Rank::new(256 + 3 * 256, DEFAULT_MIN_HOP_RANK_INCREASE) + ); + + // 1024 + 3 * 256 + assert_eq!( + ObjectiveFunction0::rank( + Rank::INFINITE, + Rank::new(1024, DEFAULT_MIN_HOP_RANK_INCREASE) + ), + Rank::new(1024 + 3 * 256, DEFAULT_MIN_HOP_RANK_INCREASE) + ); + } + + #[test] + #[should_panic] + fn rank_increase_infinite() { + assert_eq!( + ObjectiveFunction0::rank(Rank::INFINITE, Rank::INFINITE), + Rank::INFINITE + ); + } + + #[test] + fn empty_set() { + assert_eq!( + ObjectiveFunction0::preferred_parent(&ParentSet::default()), + None + ); + } + + #[test] + fn non_empty_set() { + use crate::wire::Ipv6Address; + + let mut parents = ParentSet::default(); + + parents.add(Parent::new( + Ipv6Address::default(), + 0, + Rank::ROOT, + Default::default(), + Ipv6Address::default(), + )); + + let mut address = Ipv6Address::default(); + address.0[15] = 1; + + parents.add(Parent::new( + address, + 0, + Rank::new(1024, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + Ipv6Address::default(), + )); + + assert_eq!( + ObjectiveFunction0::preferred_parent(&parents), + Some(&Parent::new( + Ipv6Address::default(), + 0, + Rank::ROOT, + Default::default(), + Ipv6Address::default(), + )) + ); + } +} diff --git a/src/iface/rpl/parents.rs b/src/iface/rpl/parents.rs new file mode 100644 index 00000000..724008d5 --- /dev/null +++ b/src/iface/rpl/parents.rs @@ -0,0 +1,189 @@ +use crate::wire::Ipv6Address; + +use super::{lollipop::SequenceCounter, rank::Rank}; +use crate::config::RPL_PARENTS_BUFFER_COUNT; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) struct Parent { + rank: Rank, + address: Ipv6Address, + preference: u8, + version_number: SequenceCounter, + dodag_id: Ipv6Address, +} + +impl Parent { + /// Create a new parent. + pub(crate) fn new( + address: Ipv6Address, + preference: u8, + rank: Rank, + version_number: SequenceCounter, + dodag_id: Ipv6Address, + ) -> Self { + Self { + rank, + address, + preference, + version_number, + dodag_id, + } + } + + /// Return the Rank of the parent. + pub(crate) fn rank(&self) -> &Rank { + &self.rank + } +} + +#[derive(Debug, Default)] +pub(crate) struct ParentSet { + parents: heapless::Vec, +} + +impl ParentSet { + /// Add a new parent to the parent set. The Rank of the new parent should be lower than the + /// Rank of the node that holds this parent set. + pub(crate) fn add(&mut self, parent: Parent) { + if let Some(p) = self.find_mut(parent.address) { + // Update information + *p = parent; + } else if let Err(p) = self.parents.push(parent) { + // Look for the worst parent + if let Some(worst) = self.worst_parent() { + if worst.rank().dag_rank() > parent.rank().dag_rank() { + *worst = parent; + } else { + net_debug!("could not add parent"); + } + } else { + // WARNING: there should be a worst parent, since the list of parents is not empty + unreachable!(); + } + } + } + + /// Find a parent based on its address. + pub(crate) fn find(&self, address: Ipv6Address) -> Option<&Parent> { + self.parents.iter().find(|p| p.address == address) + } + + /// Find a mutable parent based on its address. + pub(crate) fn find_mut(&mut self, address: Ipv6Address) -> Option<&mut Parent> { + self.parents.iter_mut().find(|p| p.address == address) + } + + /// Return a slice to the parent set. + pub(crate) fn parents(&self) -> &[Parent] { + &self.parents + } + + /// Find the worst parent that is currently in the parent set. + fn worst_parent(&mut self) -> Option<&mut Parent> { + let mut worst: Option<&mut Parent> = None; + + for p in self.parents.iter_mut() { + if worst.is_none() || worst.as_mut().unwrap().rank.dag_rank() < p.rank.dag_rank() { + worst = Some(p); + } + } + + worst + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_parent() { + let mut set = ParentSet::default(); + set.add(Parent::new( + Default::default(), + 0, + Rank::ROOT, + Default::default(), + Default::default(), + )); + + assert_eq!( + set.find(Default::default()), + Some(&Parent::new( + Default::default(), + 0, + Rank::ROOT, + Default::default(), + Default::default() + )) + ); + } + + #[test] + fn add_more_parents() { + use super::super::consts::DEFAULT_MIN_HOP_RANK_INCREASE; + let mut set = ParentSet::default(); + + let mut last_address = Default::default(); + for i in 0..RPL_PARENTS_BUFFER_COUNT { + let i = i as u16; + let mut address = Ipv6Address::default(); + address.0[15] = i as u8; + last_address = address; + + set.add(Parent::new( + address, + 0, + Rank::new(256 * i, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + address, + )); + + assert_eq!( + set.find(address), + Some(&Parent::new( + address, + 0, + Rank::new(256 * i, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + address, + )) + ); + } + + // This one is not added to the set, because its Rank is worse than any other parent in the + // set. + let mut address = Ipv6Address::default(); + address.0[15] = 8; + set.add(Parent::new( + address, + 0, + Rank::new(256 * 8, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + address, + )); + assert_eq!(set.find(address), None); + + /// This Parent has a better rank than the last one in the set. + let mut address = Ipv6Address::default(); + address.0[15] = 9; + set.add(Parent::new( + address, + 0, + Rank::new(0, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + address, + )); + assert_eq!( + set.find(address), + Some(&Parent::new( + address, + 0, + Rank::new(0, DEFAULT_MIN_HOP_RANK_INCREASE), + Default::default(), + address + )) + ); + assert_eq!(set.find(last_address), None); + } +} diff --git a/src/iface/rpl/rank.rs b/src/iface/rpl/rank.rs index daac198e..02a5ecf5 100644 --- a/src/iface/rpl/rank.rs +++ b/src/iface/rpl/rank.rs @@ -25,8 +25,8 @@ use super::consts::DEFAULT_MIN_HOP_RANK_INCREASE; #[derive(Debug, Clone, Copy, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Rank { - value: u16, - min_hop_rank_increase: u16, + pub(super) value: u16, + pub(super) min_hop_rank_increase: u16, } impl core::fmt::Display for Rank { @@ -46,6 +46,8 @@ impl Rank { /// 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 { + assert!(min_hop_rank_increase > 0); + Self { value, min_hop_rank_increase, diff --git a/src/lib.rs b/src/lib.rs index 1256292b..6128c231 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,6 +145,7 @@ mod config { pub const REASSEMBLY_BUFFER_COUNT: usize = 4; pub const REASSEMBLY_BUFFER_SIZE: usize = 1500; pub const RPL_RELATIONS_BUFFER_COUNT: usize = 16; + pub const RPL_PARENTS_BUFFER_COUNT: usize = 8; } #[cfg(not(test))]