%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TD
PKT["Packet Arrives"]
PKT --> TTL{"TTL = 0?"}
TTL -->|"Yes"| DROP1["DROP<br/>ICMP Time Exceeded"]
TTL -->|"No"| DEC["Decrement TTL"]
DEC --> LOOKUP["Route Lookup<br/>(Longest Prefix Match)"]
LOOKUP --> FOUND{"Route<br/>Found?"}
FOUND -->|"No"| DROP2["DROP<br/>ICMP Dest Unreachable"]
FOUND -->|"Yes"| TYPE{"Route<br/>Type?"}
TYPE -->|"Connected"| DIRECT["Direct Delivery<br/>(ARP → Send)"]
TYPE -->|"Static/Default"| FORWARD["Forward to<br/>Next Hop"]
style PKT fill:#E67E22,stroke:#2C3E50,color:#fff
style DROP1 fill:#E74C3C,stroke:#2C3E50,color:#fff
style DROP2 fill:#E74C3C,stroke:#2C3E50,color:#fff
style DIRECT fill:#16A085,stroke:#2C3E50,color:#fff
style FORWARD fill:#16A085,stroke:#2C3E50,color:#fff
691 Routing Labs: Advanced
691.1 Learning Objectives
By the end of this chapter, you will be able to:
- Implement packet forwarding logic on ESP32 with TTL decrement and route lookup
- Simulate routing table decisions using embedded C code with multiple route types
- Visualize network convergence using Python and matplotlib to understand route propagation
- Analyze packet drop scenarios including TTL expiration and missing routes
- Debug routing issues by understanding forwarding statistics and error conditions
Lab Series: - Routing Labs: Overview - Lab series introduction and quiz - Routing Labs: Fundamentals - Basic routing table commands and traceroute - Routing Labs: Algorithms - Python implementations of routing algorithms
Core Concepts: - Routing Fundamentals - Core routing theory and concepts - Routing Comprehensive Review - Advanced routing strategies
IoT Routing: - RPL Fundamentals - Low-power routing protocol - RPL Labs - Hands-on RPL implementation
Learning: - Simulations Hub - Routing simulators and tools
691.2 Prerequisites
Before working through these advanced labs, ensure you have completed:
- Routing Labs: Fundamentals - Basic routing table viewing and traceroute
- Routing Fundamentals - Static vs dynamic routing, metrics, and longest-prefix match
- Transport Fundamentals - Basic understanding of TCP/UDP and ports
Software Requirements:
- Arduino IDE with ESP32 board support
- Python 3.x with matplotlib and networkx libraries
691.3 Lab 4: ESP32 Packet Forwarding Simulator
Objective: Simulate packet forwarding with TTL decrement on ESP32.
Hardware Required:
- ESP32 development board
- USB cable
- Computer with Arduino IDE
Software Setup:
- Install ESP32 board support in Arduino IDE
- No additional libraries needed
691.3.1 Understanding the Simulation
This lab simulates how a router processes packets:
691.3.2 Complete ESP32 Code
#include <Wi-Fi.h>
// Simulated packet structure
struct IPPacket {
char source_ip[16];
char dest_ip[16];
uint8_t ttl;
uint8_t protocol;
char payload[64];
uint32_t packet_id;
};
// Simulated routing table entry
struct RouteEntry {
char destination[16];
char next_hop[16];
char interface[10];
int metric;
};
// Simulated routing table
RouteEntry routing_table[] = {
{"192.168.1.0/24", "0.0.0.0", "eth0", 0}, // Connected
{"10.0.0.0/8", "0.0.0.0", "eth1", 0}, // Connected
{"172.16.0.0/16", "10.0.0.2", "eth1", 10}, // Static
{"0.0.0.0/0", "192.168.1.1", "eth0", 1} // Default
};
const int ROUTING_TABLE_SIZE = 4;
uint32_t packets_forwarded = 0;
uint32_t packets_dropped = 0;
uint32_t ttl_expired = 0;
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n========================================");
Serial.println(" ESP32 Packet Forwarding Simulator");
Serial.println(" Routing & TTL Management Demo");
Serial.println("========================================\n");
displayRoutingTable();
Serial.println("\n=======================================");
Serial.println("Starting Packet Forwarding Simulation");
Serial.println("=======================================\n");
// Simulate various packet scenarios
simulatePacketScenarios();
displayStatistics();
}
void loop() {
// Simulation runs once in setup()
}
void displayRoutingTable() {
Serial.println("Routing Table:");
Serial.println("-----------------------------------------------------");
Serial.println("Destination Next Hop Interface Metric");
Serial.println("-----------------------------------------------------");
for (int i = 0; i < ROUTING_TABLE_SIZE; i++) {
char line[100];
sprintf(line, "%-17s %-15s %-10s %d",
routing_table[i].destination,
routing_table[i].next_hop,
routing_table[i].interface,
routing_table[i].metric);
Serial.println(line);
}
Serial.println("-----------------------------------------------------");
}
RouteEntry* lookupRoute(const char* dest_ip) {
// Simplified lookup - in reality would do longest prefix matching
// Check for local network matches (simplified)
if (strncmp(dest_ip, "192.168.1.", 10) == 0) {
return &routing_table[0]; // 192.168.1.0/24
} else if (strncmp(dest_ip, "10.", 3) == 0) {
return &routing_table[1]; // 10.0.0.0/8
} else if (strncmp(dest_ip, "172.16.", 7) == 0) {
return &routing_table[2]; // 172.16.0.0/16
} else {
return &routing_table[3]; // Default route
}
}
enum ForwardResult {
FORWARDED,
TTL_EXPIRED,
NO_ROUTE
};
ForwardResult forwardPacket(IPPacket* packet) {
Serial.println("\n-----------------------------------------");
Serial.printf("| Packet ID: %lu\n", packet->packet_id);
Serial.println("-----------------------------------------");
Serial.printf(" Source: %s -> Destination: %s\n",
packet->source_ip, packet->dest_ip);
Serial.printf(" TTL: %d Protocol: %d\n", packet->ttl, packet->protocol);
Serial.printf(" Payload: %s\n", packet->payload);
// Step 1: Check TTL
if (packet->ttl == 0) {
Serial.println(" X Action: DROP (TTL expired)");
Serial.println(" -> Would send ICMP Time Exceeded to source");
ttl_expired++;
packets_dropped++;
return TTL_EXPIRED;
}
// Step 2: Decrement TTL
packet->ttl--;
Serial.printf(" -> TTL decremented to %d\n", packet->ttl);
// Step 3: Route lookup
RouteEntry* route = lookupRoute(packet->dest_ip);
if (route == NULL) {
Serial.println(" X Action: DROP (No route to destination)");
Serial.println(" -> Would send ICMP Destination Unreachable");
packets_dropped++;
return NO_ROUTE;
}
// Step 4: Forward packet
Serial.printf(" OK Route found: %s\n", route->destination);
if (strcmp(route->next_hop, "0.0.0.0") == 0) {
Serial.printf(" -> Direct delivery on %s\n", route->interface);
} else {
Serial.printf(" -> Forward to next hop: %s via %s\n",
route->next_hop, route->interface);
}
Serial.printf(" OK Packet forwarded (metric: %d)\n", route->metric);
packets_forwarded++;
return FORWARDED;
}
void simulatePacketScenarios() {
IPPacket packet;
packet.protocol = 6; // TCP
// Scenario 1: Local network packet
Serial.println("\n=== Scenario 1: Local Network ===");
strcpy(packet.source_ip, "192.168.1.100");
strcpy(packet.dest_ip, "192.168.1.50");
packet.ttl = 64;
packet.packet_id = 1001;
strcpy(packet.payload, "HTTP Request");
forwardPacket(&packet);
// Scenario 2: Remote network via static route
Serial.println("\n\n=== Scenario 2: Static Route ===");
strcpy(packet.source_ip, "192.168.1.100");
strcpy(packet.dest_ip, "172.16.50.100");
packet.ttl = 64;
packet.packet_id = 1002;
strcpy(packet.payload, "IoT Sensor Data");
forwardPacket(&packet);
// Scenario 3: Internet via default route
Serial.println("\n\n=== Scenario 3: Default Route (Internet) ===");
strcpy(packet.source_ip, "192.168.1.100");
strcpy(packet.dest_ip, "8.8.8.8");
packet.ttl = 64;
packet.packet_id = 1003;
strcpy(packet.payload, "DNS Query");
forwardPacket(&packet);
// Scenario 4: TTL expiration
Serial.println("\n\n=== Scenario 4: TTL Expiration ===");
strcpy(packet.source_ip, "192.168.1.100");
strcpy(packet.dest_ip, "10.0.0.50");
packet.ttl = 1; // Will expire after decrement
packet.packet_id = 1004;
strcpy(packet.payload, "Data packet");
forwardPacket(&packet);
forwardPacket(&packet); // Second hop - TTL will be 0
// Scenario 5: Multiple hops
Serial.println("\n\n=== Scenario 5: Multiple Hops (TTL tracking) ===");
strcpy(packet.source_ip, "192.168.1.100");
strcpy(packet.dest_ip, "10.0.0.50");
packet.ttl = 5;
packet.packet_id = 1005;
strcpy(packet.payload, "Multi-hop packet");
Serial.println("Simulating packet traverse across multiple routers:");
for (int hop = 1; hop <= 5; hop++) {
Serial.printf("\n--- Hop %d ---\n", hop);
ForwardResult result = forwardPacket(&packet);
if (result != FORWARDED) {
break;
}
}
}
void displayStatistics() {
Serial.println("\n\n========================================");
Serial.println(" Forwarding Statistics");
Serial.println("========================================");
Serial.printf(" Packets Forwarded: %lu\n", packets_forwarded);
Serial.printf(" Packets Dropped: %lu\n", packets_dropped);
Serial.printf(" TTL Expired: %lu\n", ttl_expired);
Serial.printf(" Total Processed: %lu\n",
packets_forwarded + packets_dropped);
if (packets_forwarded + packets_dropped > 0) {
float success_rate = (float)packets_forwarded /
(packets_forwarded + packets_dropped) * 100.0;
Serial.printf(" Success Rate: %.1f%%\n", success_rate);
}
Serial.println("\n=======================================");
Serial.println("Simulation Complete");
Serial.println("=======================================\n");
}691.3.3 Expected Serial Monitor Output
========================================
ESP32 Packet Forwarding Simulator
Routing & TTL Management Demo
========================================
Routing Table:
-----------------------------------------------------
Destination Next Hop Interface Metric
-----------------------------------------------------
192.168.1.0/24 0.0.0.0 eth0 0
10.0.0.0/8 0.0.0.0 eth1 0
172.16.0.0/16 10.0.0.2 eth1 10
0.0.0.0/0 192.168.1.1 eth0 1
-----------------------------------------------------
=======================================
Starting Packet Forwarding Simulation
=======================================
=== Scenario 1: Local Network ===
-----------------------------------------
| Packet ID: 1001
-----------------------------------------
Source: 192.168.1.100 -> Destination: 192.168.1.50
TTL: 64 Protocol: 6
Payload: HTTP Request
-> TTL decremented to 63
OK Route found: 192.168.1.0/24
-> Direct delivery on eth0
OK Packet forwarded (metric: 0)
=== Scenario 2: Static Route ===
-----------------------------------------
| Packet ID: 1002
-----------------------------------------
Source: 192.168.1.100 -> Destination: 172.16.50.100
TTL: 64 Protocol: 6
Payload: IoT Sensor Data
-> TTL decremented to 63
OK Route found: 172.16.0.0/16
-> Forward to next hop: 10.0.0.2 via eth1
OK Packet forwarded (metric: 10)
[... more scenarios ...]
691.3.4 Learning Outcomes
- See TTL decrement in action
- Understand routing table lookup process
- Observe different forwarding decisions (connected, static, default)
- Visualize packet drop scenarios
691.4 Lab 5: Python Network Convergence Simulator
Objective: Visualize routing protocol convergence and link failure recovery.
691.4.1 Setup
pip install matplotlib networkx691.4.2 Understanding Convergence
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
graph TD
subgraph Round0["Round 0: Initial State"]
R0A["R1<br/>Knows: R2, R3"]
R0B["R2<br/>Knows: R1, R4"]
R0C["R3<br/>Knows: R1, R4"]
R0D["R4<br/>Knows: R2, R3"]
end
subgraph Round1["Round 1: Exchange"]
R1A["R1<br/>Knows: R2, R3, R4"]
R1B["R2<br/>Knows: R1, R3, R4"]
R1C["R3<br/>Knows: R1, R2, R4"]
R1D["R4<br/>Knows: R1, R2, R3"]
end
subgraph Round2["Round 2: Converged"]
R2A["R1<br/>All routes optimal"]
R2B["R2<br/>All routes optimal"]
R2C["R3<br/>All routes optimal"]
R2D["R4<br/>All routes optimal"]
end
Round0 -->|"Tables exchanged"| Round1
Round1 -->|"No changes"| Round2
style R0A fill:#E67E22,stroke:#16A085,color:#fff
style R1A fill:#16A085,stroke:#16A085,color:#fff
style R2A fill:#2C3E50,stroke:#16A085,color:#fff
691.4.3 Python Simulation Code
"""
Network Convergence Simulator
Demonstrates distance vector routing protocol convergence
"""
import matplotlib.pyplot as plt
import networkx as nx
from collections import defaultdict
class DistanceVectorRouter:
"""Simulates a router running distance vector protocol"""
def __init__(self, name):
self.name = name
self.neighbors = {} # neighbor_name: cost
self.routing_table = {} # destination: (cost, next_hop)
def add_neighbor(self, neighbor_name, cost):
"""Add a directly connected neighbor"""
self.neighbors[neighbor_name] = cost
self.routing_table[neighbor_name] = (cost, neighbor_name)
def receive_update(self, from_neighbor, neighbor_table):
"""
Process routing update from a neighbor
Returns True if routing table changed
"""
changed = False
cost_to_neighbor = self.neighbors.get(from_neighbor, float('inf'))
for destination, (dest_cost, _) in neighbor_table.items():
if destination == self.name:
continue
new_cost = cost_to_neighbor + dest_cost
current = self.routing_table.get(destination)
if current is None or new_cost < current[0]:
self.routing_table[destination] = (new_cost, from_neighbor)
changed = True
return changed
def get_routing_table(self):
"""Return copy of routing table for sharing"""
return dict(self.routing_table)
class NetworkSimulator:
"""Simulates a network of distance vector routers"""
def __init__(self):
self.routers = {}
self.history = [] # Track convergence history
def add_router(self, name):
"""Add a router to the network"""
self.routers[name] = DistanceVectorRouter(name)
self.routers[name].routing_table[name] = (0, name)
def add_link(self, router1, router2, cost):
"""Add a bidirectional link between routers"""
self.routers[router1].add_neighbor(router2, cost)
self.routers[router2].add_neighbor(router1, cost)
def run_convergence(self, max_rounds=10):
"""
Run distance vector convergence
Returns number of rounds to converge
"""
print("\nRunning distance vector convergence...")
print("=" * 60)
for round_num in range(max_rounds):
print(f"\n{'=' * 60}")
print(f"Round {round_num}")
print(f"{'=' * 60}")
# Snapshot current state
self.history.append(self._get_network_state())
# Each router sends updates to neighbors
any_change = False
updates = {}
# Collect all updates first
for name, router in self.routers.items():
updates[name] = router.get_routing_table()
# Apply updates
for name, router in self.routers.items():
for neighbor in router.neighbors:
if router.receive_update(neighbor, updates[neighbor]):
any_change = True
# Print current routing tables
self._print_routing_tables()
if not any_change and round_num > 0:
print(f"\nConverged in {round_num} rounds")
return round_num
print(f"\nDid not converge in {max_rounds} rounds")
return max_rounds
def _get_network_state(self):
"""Capture current network state for visualization"""
state = {}
for name, router in self.routers.items():
state[name] = dict(router.routing_table)
return state
def _print_routing_tables(self):
"""Print all routing tables"""
for name, router in self.routers.items():
print(f"\nRouting Table for {name}:")
print("Destination Cost Next Hop")
print("-" * 40)
for dest, (cost, next_hop) in sorted(router.routing_table.items()):
print(f"{dest:<15} {cost:<6} {next_hop}")
def simulate_link_failure(self, router1, router2):
"""Simulate a link failure between two routers"""
print(f"\n{'=' * 60}")
print(f"Link Failure: {router1}-{router2} link goes down")
print(f"{'=' * 60}")
# Remove neighbor relationship
if router2 in self.routers[router1].neighbors:
del self.routers[router1].neighbors[router2]
if router1 in self.routers[router2].neighbors:
del self.routers[router2].neighbors[router1]
# Mark routes via failed link as invalid
for name, router in self.routers.items():
invalid_dests = []
for dest, (cost, next_hop) in router.routing_table.items():
if next_hop == router2 and name == router1:
invalid_dests.append(dest)
elif next_hop == router1 and name == router2:
invalid_dests.append(dest)
for dest in invalid_dests:
del router.routing_table[dest]
def visualize_topology(self):
"""Create network topology visualization"""
G = nx.Graph()
# Add nodes and edges
for name, router in self.routers.items():
G.add_node(name)
for neighbor, cost in router.neighbors.items():
G.add_edge(name, neighbor, weight=cost)
# Draw network
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G, seed=42)
nx.draw_networkx_nodes(G, pos, node_size=700,
node_color='#2C3E50')
nx.draw_networkx_labels(G, pos, font_size=12,
font_color='white')
nx.draw_networkx_edges(G, pos, width=2,
edge_color='#16A085')
# Add edge labels (costs)
edge_labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels,
font_size=10)
plt.title("Network Topology", fontsize=14)
plt.axis('off')
plt.tight_layout()
plt.savefig('network_topology.png', dpi=150)
plt.show()
print("Saved: network_topology.png")
def main():
"""Run the network convergence simulation"""
print("Network Convergence Simulator")
print("=" * 60)
# Create network
sim = NetworkSimulator()
# Add routers
for name in ['R1', 'R2', 'R3', 'R4', 'R5']:
sim.add_router(name)
# Add links (creating a mesh topology)
sim.add_link('R1', 'R2', 1)
sim.add_link('R1', 'R3', 5)
sim.add_link('R2', 'R4', 2)
sim.add_link('R3', 'R4', 1)
sim.add_link('R4', 'R5', 3)
print("\nInitial Network Topology:")
print("""
R1 ---- 1 ---- R2
| |
5 2
| |
R3 ---- 1 ---- R4 ---- 3 ---- R5
""")
# Run convergence
rounds = sim.run_convergence()
# Simulate link failure
sim.simulate_link_failure('R1', 'R2')
print("\nReconverging after link failure...")
sim.run_convergence()
# Visualize (optional - requires display)
try:
sim.visualize_topology()
except Exception as e:
print(f"Visualization skipped: {e}")
if __name__ == "__main__":
main()691.4.4 Expected Output
Network Convergence Simulator
======================================================================
Initial Network Topology:
R1 ---- 1 ---- R2
| |
5 2
| |
R3 ---- 1 ---- R4 ---- 3 ---- R5
Running distance vector convergence...
============================================================
============================================================
Round 0
============================================================
Routing Table for R1:
Destination Cost Next Hop
----------------------------------------
R1 0 R1
R2 1 R2
R3 5 R3
Routing Table for R2:
Destination Cost Next Hop
----------------------------------------
R1 1 R1
R2 0 R2
R4 2 R4
[... continues ...]
============================================================
Round 3
============================================================
Routing Table for R1:
Destination Cost Next Hop
----------------------------------------
R1 0 R1
R2 1 R2
R3 4 R2
R4 3 R2
R5 6 R2
Converged in 3 rounds
============================================================
Link Failure: R1-R2 link goes down
============================================================
Reconverging after link failure...
[... reconvergence output ...]
691.4.5 Key Concepts Demonstrated
- Distance Vector Propagation: Each round, knowledge spreads one hop further
- Bellman-Ford Algorithm: Cost via neighbor = cost_to_neighbor + neighbor’s_cost
- Convergence Detection: No changes between rounds indicates convergence
- Link Failure Recovery: Routes via failed link are removed, new paths discovered
691.5 Routing Metrics in IoT Networks
Different routing protocols use different metrics to determine the best path. Understanding these metrics helps you choose the right protocol for your IoT deployment.
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
graph TD
subgraph Metric1["Hop Count Metric"]
R1A["Router A"]
R1B["Router B"]
R1C["Router C"]
R1D["Destination"]
R1A -->|"1 hop"| R1B
R1B -->|"1 hop"| R1C
R1C -->|"1 hop"| R1D
R1A -.->|"Cost: 3 hops"| R1D
end
subgraph Metric2["ETX Metric (Expected Transmission Count)"]
R2A["Router A"]
R2B["Router B<br/>PRR 80%<br/>ETX 1.25"]
R2C["Router C<br/>PRR 90%<br/>ETX 1.11"]
R2D["Destination"]
R2A -->|"ETX 1.25"| R2B
R2B -->|"ETX 1.11"| R2C
R2C -->|"ETX 1.0"| R2D
R2A -.->|"Total ETX: 3.36"| R2D
end
subgraph Metric3["Latency Metric"]
R3A["Router A"]
R3B["Router B<br/>10ms"]
R3C["Router C<br/>15ms"]
R3D["Destination"]
R3A -->|"10ms"| R3B
R3B -->|"15ms"| R3C
R3C -->|"5ms"| R3D
R3A -.->|"Total: 30ms"| R3D
end
style R1A fill:#2C3E50,stroke:#16A085,color:#fff
style R1B fill:#16A085,stroke:#16A085,color:#fff
style R1C fill:#16A085,stroke:#16A085,color:#fff
style R1D fill:#E67E22,stroke:#16A085,color:#fff
style R2A fill:#2C3E50,stroke:#16A085,color:#fff
style R2B fill:#16A085,stroke:#16A085,color:#fff
style R2C fill:#16A085,stroke:#16A085,color:#fff
style R2D fill:#E67E22,stroke:#16A085,color:#fff
style R3A fill:#2C3E50,stroke:#16A085,color:#fff
style R3B fill:#16A085,stroke:#16A085,color:#fff
style R3C fill:#16A085,stroke:#16A085,color:#fff
style R3D fill:#E67E22,stroke:#16A085,color:#fff
Use Hop Count when:
- Network links are reliable (wired connections)
- Minimizing routing overhead is critical
- Simple routing decisions are sufficient
Use ETX when:
- Wireless links with variable quality
- Retransmissions impact performance
- Link reliability varies significantly (typical in IoT)
Use Latency when:
- Real-time applications (video, voice, industrial control)
- Delay-sensitive IoT use cases
- Network congestion is a concern
For IoT sensor networks, ETX is often the best choice because wireless links experience packet loss, and minimizing retransmissions saves battery power.
691.6 Summary
- ESP32 packet forwarding simulation demonstrates TTL decrement, route lookup, and forwarding decisions in embedded systems
- Routing table structures include destination network, next hop, interface, and metric for making forwarding decisions
- Python convergence simulation visualizes how distance vector protocols propagate routing information across a network
- Link failure recovery shows how routers automatically discover new paths when existing routes become unavailable
- Routing metrics (hop count, ETX, latency) serve different purposes depending on network characteristics and application requirements
- Forwarding statistics help diagnose routing issues by tracking successful forwards, drops, and TTL expirations
691.7 What’s Next
Continue to Routing Labs: Algorithms for Python implementations of:
- Routing table simulator with longest prefix matching
- Dijkstra’s shortest path algorithm (link-state routing)
- Distance vector routing protocol (RIP simulation)
Or return to Routing Labs: Overview for quiz questions testing your understanding.