# Compare RPL objective functions and candidate paths

Compare real MRHOF and OF0 parent records, then explain how their state differs from longest-prefix, Dijkstra and distance-vector worksheets.

## Run on Linux x86-64 with Docker and X11

The image, Java, compiler and simulator ran on this host under Apptainer.
Docker is unavailable here: the laptop Docker invocation is syntax-reviewed,
not claimed as laptop-tested. Windows, macOS and ARM display setup is outside
this recipe. No paid service or account is required.

Download `lab-files.tar.gz` from this lab page. In a terminal:

```bash
mkdir cooja-lab
cd cooja-lab
tar -xzf ~/Downloads/lab-files.tar.gz
git clone --depth 1 --branch release/v4.9 https://github.com/contiki-ng/contiki-ng.git contiki-ng
test "$(git -C contiki-ng rev-parse HEAD)" = c20b12cd2db707d6c07918f8b26cfeb52cf298ca
git -C contiki-ng submodule update --init --depth 1 tools/cooja
test "$(git -C contiki-ng/tools/cooja rev-parse HEAD)" = 33d41ae9f8acd6075fb903b0bcd5b4122bad8d8f
mkdir -p jdk17 home/contiki-ng
curl -fL 'https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.20.1%2B1/OpenJDK17U-jdk_x64_linux_hotspot_17.0.20.1_1.tar.gz' -o jdk17.tar.gz
echo '3808d1d15e3ec6bd5b84057fb5d84c33d8a1536a258146bcea2e603fc726e08e  jdk17.tar.gz' | sha256sum -c -
tar -xzf jdk17.tar.gz --strip-components=1 -C jdk17
xhost +si:localuser:$(id -un)
bash cooja-rpl-objective-functions/docker-launch.sh
# After closing Cooja:
xhost -si:localuser:$(id -un)
```

The launcher binds the packet at `/lab`. Cooja loads `/lab/cooja-rpl-objective-functions.csc`
and compiles the included unmodified upstream C files. The project header enables
logging and any explicitly documented parameter changes. The supplied Makefiles
expect the recipe's `/home/user/contiki-ng` mount. The first Gradle build requires
Internet. To use your own native Java 17 installation, set CONTIKI in the supplied
Makefiles to your checkout and open the CSC with that release's Cooja.

The script starts automatically and stops at `TEST OK` or `TEST FAILED`. The GUI
stays open. Use **Mote output → Filter** to show the rows named in the steps;
clear the filter to inspect other messages. **File → Open simulation → Browse...**
loads another CSC. Reopen the original CSC for a fresh seed-1 run.
Times are simulated times, not wall-clock times. `expected-output.txt` is the
unaltered headless serial/test log, including actual measurements and the test result.

For headless Docker execution, replace `--gui --autostart` in the launcher with
`--no-gui --logdir=/lab/run-output` and remove the display requirement/mount.
Cooja writes `COOJA.testlog` under that writable output directory.

## Controlled simulator comparison

Both CSCs use root 1 (0,0), nodes 2 (-30,25), 3 (30,25), 4 (-60,55),
5 (0,55), 6 (60,55); seed 1; UDGM 50/100 m, transmit success 1,
receive success 0.80. The files `MRHOF/project-conf.h` and `OF0/project-conf.h`
select RPL_CONF_OF_OCP 1 and 0 respectively and include both functions in
RPL_CONF_SUPPORTED_OFS. All application C is unchanged upstream rpl-udp.

Read neighbor Rank, raw link metric and candidate Rank in `rpl-nbr`.
The real snapshots at 140.065 s are:

| Function | Candidate 2 | Candidate 3 | Chosen parent / Rank |
|---|---|---|---|
| MRHOF | 310 + 159 → 469 | 286 + 249 → 535 | 2 / 469 |
| OF0 | 512, metric 187 → 1024 | 768, metric 181 → 1280 | 2 / 1024 |

The link metric is fixed-point, not a percentage. MRHOF in this build uses
ETX units with divisor 128. OF0 computes its own rank increase; do not add
187 to 512 and expect 1024. Read the implementation in
`os/net/routing/rpl-lite/rpl-of0.c` when explaining its step calculation.
Both runs deliver 78 requests at the root and replies to every client. The
scheduled ping has a 100 ms MRHOF or 94 ms OF0 return delay. These are one-run
observations under model loss and retransmissions, not confidence intervals,
battery-life estimates or evidence that one function is universally faster.

## Preserve the original longest-prefix trace

Use gateways A /0, B 10.0.0.0/8, C 10.2.0.0/16, D 10.2.4.0/24.
For 10.2.4.77 list /0,/8,/16,/24 and select D; for 10.2.9.12 select C;
for 10.8.1.5 select B; for 198.51.100.20 select A. Explain why a lower
metric for B cannot override D's /24. These are worksheet routes, not mesh
IPv4 routes. Longest-prefix lookup selects a forwarding row; it does not
compute RPL parent Rank.

## Preserve the original Dijkstra trace

Undirected weights: R1–R2=1, R1–R3=5, R2–R4=2, R3–R4=1, R4–R5=3.
Start at R1; write settled, frontier, predecessor and next-hop columns:

| Settle | Frontier changes | Reason |
|---|---|---|
| R1, 0 | R2=1, R3=5 | direct neighbors |
| R2, 1 | R4=3 via R2 | 1+2 |
| R4, 3 | R3 improves 5→4; R5=6 | 3+1 and 3+3 |
| R3, 4 | no lower candidate | current best |
| R5, 6 | none | all reachable nodes settled |

R1's first hop to R3/R4/R5 is R2. Remove R1–R2 and recompute:
R3=5 via R3, R4=6 via R3, R2=8 via R3/R4, R5=9 via R3/R4.
All those first hops now start at R3. The improved tentative path is required
in your record; a final tree alone omits it. Dijkstra assumes a known current
topology; real link-state protocols still need flooding and freshness evidence.

## Preserve the original distance-vector rounds and withdrawal

For unit-cost R1–R2–R3, round 0 knows self and neighbors. Round 1 teaches
R1 about R3 at cost 2 via R2 (and the reverse). Round 2 has no changes.
Now remove R2–R3. R2 invalidates its direct R3 route while R1 initially
still holds stale cost 2. With poisoned reverse, R1 advertises that learned
route back to R2 as infinity; with split horizon, it omits it. R2 advertises
its withdrawal to R1, which then marks R3 unreachable. State the update
rounds explicitly; these rules are not measured RPL timing. DSDV adds
destination sequence-number freshness: a newer sequence wins before hop
count, so a stale cheaper route cannot override a fresh withdrawal.

Compare records: LPM needs prefixes; link-state needs a current topology;
distance-vector needs fresh neighbor advertisements; RPL needs compatible
DIOs, Rank, eligible parents, link evidence, Trickle and DAO/source-route state.
DSR discovers/caches paths on demand; ZRP combines a proactive local zone with
reactive searches beyond it. None of these labels proves delivery or a return
path. Add state/memory cost and a stale-state failure to every comparison row.


## Tested version

Contiki-NG release/v4.9 c20b12cd, Cooja 4.8 (2022071901), Temurin 17.0.20.1, image sha256:b14d5afb0a2a852d9e72bbed607ead03f6ccc5f4d4dee44f0799110be2f4b609
