Skip to content

Commit 8f4820f

Browse files
authored
Merge pull request #798 from thvdveld/rpl-objective-function
RPL: add objective function and parent set
2 parents 7b4246d + f68603d commit 8f4820f

File tree

8 files changed

+335
-2
lines changed

8 files changed

+335
-2
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ rpl-relations-buffer-count-32 = []
223223
rpl-relations-buffer-count-64 = []
224224
rpl-relations-buffer-count-128 = []
225225

226+
rpl-parents-buffer-count-2 = []
227+
rpl-parents-buffer-count-4 = []
228+
rpl-parents-buffer-count-8 = [] # Default
229+
rpl-parents-buffer-count-16 = []
230+
rpl-parents-buffer-count-32 = []
231+
226232
# END AUTOGENERATED CONFIG FEATURES
227233

228234
[[example]]

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static CONFIGS: &[(&str, usize)] = &[
1919
("DNS_MAX_SERVER_COUNT", 1),
2020
("DNS_MAX_NAME_SIZE", 255),
2121
("RPL_RELATIONS_BUFFER_COUNT", 16),
22+
("RPL_PARENTS_BUFFER_COUNT", 8),
2223
// END AUTOGENERATED CONFIG FEATURES
2324
];
2425

gen_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def feature(name, default, min, max, pow2=None):
4040
feature("dns_max_server_count", default=1, min=1, max=32, pow2=4)
4141
feature("dns_max_name_size", default=255, min=64, max=255, pow2=True)
4242
feature("rpl_relations_buffer_count", default=16, min=1, max=128, pow2=True)
43+
feature("rpl_parents_buffer_count", default=8, min=2, max=32, pow2=True)
4344

4445
# ========= Update Cargo.toml
4546

src/iface/rpl/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
mod consts;
44
mod lollipop;
5+
mod of0;
6+
mod parents;
57
mod rank;
68
mod relations;
79
mod trickle;

src/iface/rpl/of0.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use super::parents::*;
2+
use super::rank::Rank;
3+
4+
pub struct ObjectiveFunction0;
5+
6+
pub(crate) trait ObjectiveFunction {
7+
const OCP: u16;
8+
9+
/// Return the new calculated Rank, based on information from the parent.
10+
fn rank(current_rank: Rank, parent_rank: Rank) -> Rank;
11+
12+
/// Return the preferred parent from a given parent set.
13+
fn preferred_parent(parent_set: &ParentSet) -> Option<&Parent>;
14+
}
15+
16+
impl ObjectiveFunction0 {
17+
const OCP: u16 = 0;
18+
19+
const RANK_STRETCH: u16 = 0;
20+
const RANK_FACTOR: u16 = 1;
21+
const RANK_STEP: u16 = 3;
22+
23+
fn rank_increase(parent_rank: Rank) -> u16 {
24+
(Self::RANK_FACTOR * Self::RANK_STEP + Self::RANK_STRETCH)
25+
* parent_rank.min_hop_rank_increase
26+
}
27+
}
28+
29+
impl ObjectiveFunction for ObjectiveFunction0 {
30+
const OCP: u16 = 0;
31+
32+
fn rank(_: Rank, parent_rank: Rank) -> Rank {
33+
assert_ne!(parent_rank, Rank::INFINITE);
34+
35+
Rank::new(
36+
parent_rank.value + Self::rank_increase(parent_rank),
37+
parent_rank.min_hop_rank_increase,
38+
)
39+
}
40+
41+
fn preferred_parent(parent_set: &ParentSet) -> Option<&Parent> {
42+
let mut pref_parent: Option<&Parent> = None;
43+
44+
for parent in parent_set.parents() {
45+
if pref_parent.is_none() || parent.rank() < pref_parent.unwrap().rank() {
46+
pref_parent = Some(parent);
47+
}
48+
}
49+
50+
pref_parent
51+
}
52+
}
53+
54+
#[cfg(test)]
55+
mod tests {
56+
use crate::iface::rpl::consts::DEFAULT_MIN_HOP_RANK_INCREASE;
57+
58+
use super::*;
59+
60+
#[test]
61+
fn rank_increase() {
62+
// 256 (root) + 3 * 256
63+
assert_eq!(
64+
ObjectiveFunction0::rank(Rank::INFINITE, Rank::ROOT),
65+
Rank::new(256 + 3 * 256, DEFAULT_MIN_HOP_RANK_INCREASE)
66+
);
67+
68+
// 1024 + 3 * 256
69+
assert_eq!(
70+
ObjectiveFunction0::rank(
71+
Rank::INFINITE,
72+
Rank::new(1024, DEFAULT_MIN_HOP_RANK_INCREASE)
73+
),
74+
Rank::new(1024 + 3 * 256, DEFAULT_MIN_HOP_RANK_INCREASE)
75+
);
76+
}
77+
78+
#[test]
79+
#[should_panic]
80+
fn rank_increase_infinite() {
81+
assert_eq!(
82+
ObjectiveFunction0::rank(Rank::INFINITE, Rank::INFINITE),
83+
Rank::INFINITE
84+
);
85+
}
86+
87+
#[test]
88+
fn empty_set() {
89+
assert_eq!(
90+
ObjectiveFunction0::preferred_parent(&ParentSet::default()),
91+
None
92+
);
93+
}
94+
95+
#[test]
96+
fn non_empty_set() {
97+
use crate::wire::Ipv6Address;
98+
99+
let mut parents = ParentSet::default();
100+
101+
parents.add(Parent::new(
102+
Ipv6Address::default(),
103+
0,
104+
Rank::ROOT,
105+
Default::default(),
106+
Ipv6Address::default(),
107+
));
108+
109+
let mut address = Ipv6Address::default();
110+
address.0[15] = 1;
111+
112+
parents.add(Parent::new(
113+
address,
114+
0,
115+
Rank::new(1024, DEFAULT_MIN_HOP_RANK_INCREASE),
116+
Default::default(),
117+
Ipv6Address::default(),
118+
));
119+
120+
assert_eq!(
121+
ObjectiveFunction0::preferred_parent(&parents),
122+
Some(&Parent::new(
123+
Ipv6Address::default(),
124+
0,
125+
Rank::ROOT,
126+
Default::default(),
127+
Ipv6Address::default(),
128+
))
129+
);
130+
}
131+
}

src/iface/rpl/parents.rs

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
use crate::wire::Ipv6Address;
2+
3+
use super::{lollipop::SequenceCounter, rank::Rank};
4+
use crate::config::RPL_PARENTS_BUFFER_COUNT;
5+
6+
#[derive(Debug, Clone, Copy, PartialEq)]
7+
pub(crate) struct Parent {
8+
rank: Rank,
9+
address: Ipv6Address,
10+
preference: u8,
11+
version_number: SequenceCounter,
12+
dodag_id: Ipv6Address,
13+
}
14+
15+
impl Parent {
16+
/// Create a new parent.
17+
pub(crate) fn new(
18+
address: Ipv6Address,
19+
preference: u8,
20+
rank: Rank,
21+
version_number: SequenceCounter,
22+
dodag_id: Ipv6Address,
23+
) -> Self {
24+
Self {
25+
rank,
26+
address,
27+
preference,
28+
version_number,
29+
dodag_id,
30+
}
31+
}
32+
33+
/// Return the Rank of the parent.
34+
pub(crate) fn rank(&self) -> &Rank {
35+
&self.rank
36+
}
37+
}
38+
39+
#[derive(Debug, Default)]
40+
pub(crate) struct ParentSet {
41+
parents: heapless::Vec<Parent, { RPL_PARENTS_BUFFER_COUNT }>,
42+
}
43+
44+
impl ParentSet {
45+
/// Add a new parent to the parent set. The Rank of the new parent should be lower than the
46+
/// Rank of the node that holds this parent set.
47+
pub(crate) fn add(&mut self, parent: Parent) {
48+
if let Some(p) = self.find_mut(parent.address) {
49+
// Update information
50+
*p = parent;
51+
} else if let Err(p) = self.parents.push(parent) {
52+
// Look for the worst parent
53+
if let Some(worst) = self.worst_parent() {
54+
if worst.rank().dag_rank() > parent.rank().dag_rank() {
55+
*worst = parent;
56+
} else {
57+
net_debug!("could not add parent");
58+
}
59+
} else {
60+
// WARNING: there should be a worst parent, since the list of parents is not empty
61+
unreachable!();
62+
}
63+
}
64+
}
65+
66+
/// Find a parent based on its address.
67+
pub(crate) fn find(&self, address: Ipv6Address) -> Option<&Parent> {
68+
self.parents.iter().find(|p| p.address == address)
69+
}
70+
71+
/// Find a mutable parent based on its address.
72+
pub(crate) fn find_mut(&mut self, address: Ipv6Address) -> Option<&mut Parent> {
73+
self.parents.iter_mut().find(|p| p.address == address)
74+
}
75+
76+
/// Return a slice to the parent set.
77+
pub(crate) fn parents(&self) -> &[Parent] {
78+
&self.parents
79+
}
80+
81+
/// Find the worst parent that is currently in the parent set.
82+
fn worst_parent(&mut self) -> Option<&mut Parent> {
83+
let mut worst: Option<&mut Parent> = None;
84+
85+
for p in self.parents.iter_mut() {
86+
if worst.is_none() || worst.as_mut().unwrap().rank.dag_rank() < p.rank.dag_rank() {
87+
worst = Some(p);
88+
}
89+
}
90+
91+
worst
92+
}
93+
}
94+
95+
#[cfg(test)]
96+
mod tests {
97+
use super::*;
98+
99+
#[test]
100+
fn add_parent() {
101+
let mut set = ParentSet::default();
102+
set.add(Parent::new(
103+
Default::default(),
104+
0,
105+
Rank::ROOT,
106+
Default::default(),
107+
Default::default(),
108+
));
109+
110+
assert_eq!(
111+
set.find(Default::default()),
112+
Some(&Parent::new(
113+
Default::default(),
114+
0,
115+
Rank::ROOT,
116+
Default::default(),
117+
Default::default()
118+
))
119+
);
120+
}
121+
122+
#[test]
123+
fn add_more_parents() {
124+
use super::super::consts::DEFAULT_MIN_HOP_RANK_INCREASE;
125+
let mut set = ParentSet::default();
126+
127+
let mut last_address = Default::default();
128+
for i in 0..RPL_PARENTS_BUFFER_COUNT {
129+
let i = i as u16;
130+
let mut address = Ipv6Address::default();
131+
address.0[15] = i as u8;
132+
last_address = address;
133+
134+
set.add(Parent::new(
135+
address,
136+
0,
137+
Rank::new(256 * i, DEFAULT_MIN_HOP_RANK_INCREASE),
138+
Default::default(),
139+
address,
140+
));
141+
142+
assert_eq!(
143+
set.find(address),
144+
Some(&Parent::new(
145+
address,
146+
0,
147+
Rank::new(256 * i, DEFAULT_MIN_HOP_RANK_INCREASE),
148+
Default::default(),
149+
address,
150+
))
151+
);
152+
}
153+
154+
// This one is not added to the set, because its Rank is worse than any other parent in the
155+
// set.
156+
let mut address = Ipv6Address::default();
157+
address.0[15] = 8;
158+
set.add(Parent::new(
159+
address,
160+
0,
161+
Rank::new(256 * 8, DEFAULT_MIN_HOP_RANK_INCREASE),
162+
Default::default(),
163+
address,
164+
));
165+
assert_eq!(set.find(address), None);
166+
167+
/// This Parent has a better rank than the last one in the set.
168+
let mut address = Ipv6Address::default();
169+
address.0[15] = 9;
170+
set.add(Parent::new(
171+
address,
172+
0,
173+
Rank::new(0, DEFAULT_MIN_HOP_RANK_INCREASE),
174+
Default::default(),
175+
address,
176+
));
177+
assert_eq!(
178+
set.find(address),
179+
Some(&Parent::new(
180+
address,
181+
0,
182+
Rank::new(0, DEFAULT_MIN_HOP_RANK_INCREASE),
183+
Default::default(),
184+
address
185+
))
186+
);
187+
assert_eq!(set.find(last_address), None);
188+
}
189+
}

src/iface/rpl/rank.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use super::consts::DEFAULT_MIN_HOP_RANK_INCREASE;
2525
#[derive(Debug, Clone, Copy, Eq)]
2626
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
2727
pub struct Rank {
28-
value: u16,
29-
min_hop_rank_increase: u16,
28+
pub(super) value: u16,
29+
pub(super) min_hop_rank_increase: u16,
3030
}
3131

3232
impl core::fmt::Display for Rank {
@@ -46,6 +46,8 @@ impl Rank {
4646
/// The `MinHopRankIncrease` is used for calculating the integer part for comparing to other
4747
/// Ranks.
4848
pub const fn new(value: u16, min_hop_rank_increase: u16) -> Self {
49+
assert!(min_hop_rank_increase > 0);
50+
4951
Self {
5052
value,
5153
min_hop_rank_increase,

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ mod config {
145145
pub const REASSEMBLY_BUFFER_COUNT: usize = 4;
146146
pub const REASSEMBLY_BUFFER_SIZE: usize = 1500;
147147
pub const RPL_RELATIONS_BUFFER_COUNT: usize = 16;
148+
pub const RPL_PARENTS_BUFFER_COUNT: usize = 8;
148149
}
149150

150151
#[cfg(not(test))]

0 commit comments

Comments
 (0)