Skip to main content

Comparison of Distance-Vector Routing (RIP) and Link-State Routing | NS3 Project 11

Comparison of Distance-Vector Routing (RIP) and Link-State Routing

1. Aim

To simulate and compare the behavior of a Distance-Vector routing protocol (RIP) and a Link-State routing protocol (OLSR) on a 6-node point-to-point network in ns-3.44, visualize packet flow using NetAnim, introduce a mid-simulation link failure to observe convergence behavior, and record throughput data for graph-based analysis.

2. Theory

2.1 Distance-Vector Routing — RIP

Routing Information Protocol (RIP) is a classical distance-vector protocol. Every router periodically broadcasts its entire routing table to its immediate neighbors. Routes are selected based on hop count, with a maximum metric of 15 hops; a value of 16 is considered infinite (unreachable). Each node builds its routing table using the Bellman-Ford algorithm by iteratively updating paths based on the cost information received from neighbors. When a link fails, the affected node must propagate the change hop-by-hop through the network, which can result in slower convergence. ns-3's RipHelper implements this behavior and supports triggered updates and split-horizon with poison reverse.

2.2 Link-State Routing — OLSR

Optimized Link State Routing (OLSR) is a proactive link-state protocol designed for ad-hoc and general IP networks. Each node floods the network with Hello and TC (Topology Control) messages to build a complete topology map. Using Dijkstra's shortest-path algorithm, each node independently computes optimal routes to all destinations. OLSR uses MultiPoint Relays (MPRs) to reduce flooding overhead. Because every node has a global view of the topology, route recomputation after a failure is faster and more accurate than in distance-vector protocols. ns-3's OlsrHelper provides a ready-to-use implementation.

2.3 NetAnim

NetAnim is the ns-3 network animator. During simulation, AnimationInterface writes packet events and node positions to an XML file. The NetAnim GUI reads this file and replays the simulation visually, allowing inspection of packet paths, node labels, and topology changes over time.

3. Network Topology

The simulation uses 6 nodes connected by Point-to-Point links with a data rate of 5 Mbps and a propagation delay of 2 ms. The topology provides two parallel paths and a diagonal shortcut:

Upper path:    N0 — N1 — N2 — N5

Lower path:    N0 — N3 — N4 — N5

Diagonal link: N2 — N4

Node N0 is the traffic source and Node N5 is the destination. UDP traffic at 1 Mbps starts at t = 20 s and ends at t = 85 s. The link N1–N2 is brought down at t = 40 s, forcing the protocols to reroute through the lower path. The link is restored at t = 65 s.

4. LLM Prompt and Tool Used

LLM Used: ChatGPT (GPT-4o)

Prompt Used:

Create an ns-3 program to compare distance-vector routing (RIP) and link-state routing (OLSR) using NetAnim visualization. Use the same 6-node topology for both protocols, generate NetAnim animation XML, create a throughput CSV for graph plotting, introduce a link failure during simulation, and print routing statistics so I can compare convergence and recovery behavior.

5. Commands to Run

Save the source file as scratch/file.cc inside your ns-3.44 folder, then execute:

./ns3 run "scratch/file.cc --protocol=RIP"

./ns3 run "scratch/file.cc --protocol=OLSR"

To open the NetAnim animation after running:

cd netanim && ./NetAnim

Load rip.xml for RIP visualization and olsr.xml for OLSR visualization.

6. Source Code

#include "ns3/applications-module.h"

#include "ns3/core-module.h"

#include "ns3/flow-monitor-module.h"

#include "ns3/internet-module.h"

#include "ns3/mobility-module.h"

#include "ns3/netanim-module.h"

#include "ns3/network-module.h"

#include "ns3/olsr-helper.h"

#include "ns3/point-to-point-module.h"

#include "ns3/rip-helper.h"

#include <fstream>

#include <string>

 

using namespace ns3;

 

NS_LOG_COMPONENT_DEFINE("RipVsOlsrComparison");

 

static Ptr<PacketSink> g_sink;

static std::ofstream g_csv;

static uint64_t g_lastTotalRx = 0;

static double g_interval = 1.0;

 

static void TraceThroughput() {

    double now = Simulator::Now().GetSeconds();

    uint64_t cur = g_sink->GetTotalRx();

    double kbps = ((cur - g_lastTotalRx) * 8.0) / (1000.0 * g_interval);

    g_csv << now << "," << kbps << "," << cur << "\n";

    g_lastTotalRx = cur;

    if (now < 89.0)

        Simulator::Schedule(Seconds(g_interval), &TraceThroughput);

}

 

static void SetInterfaceDown(Ptr<Node> node, Ptr<NetDevice> dev) {

    Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();

    uint32_t ifIndex = ipv4->GetInterfaceForDevice(dev);

    ipv4->SetDown(ifIndex);

}

 

static void SetInterfaceUp(Ptr<Node> node, Ptr<NetDevice> dev) {

    Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();

    uint32_t ifIndex = ipv4->GetInterfaceForDevice(dev);

    ipv4->SetUp(ifIndex);

}

 

int main(int argc, char* argv[]) {

    std::string protocol = "RIP";

    bool enablePcap = true;

    double simTime = 90.0;

 

    CommandLine cmd(__FILE__);

    cmd.AddValue("protocol", "RIP or OLSR", protocol);

    cmd.AddValue("enablePcap", "Enable pcap tracing", enablePcap);

    cmd.Parse(argc, argv);

 

    bool useRip = (protocol != "OLSR" && protocol != "olsr");

    if (!useRip) protocol = "OLSR"; else protocol = "RIP";

 

    NodeContainer nodes;

    nodes.Create(6);

 

    PointToPointHelper p2p;

    p2p.SetDeviceAttribute("DataRate", StringValue("5Mbps"));

    p2p.SetChannelAttribute("Delay", StringValue("2ms"));

 

    NodeContainer n01(nodes.Get(0), nodes.Get(1));

    NodeContainer n12(nodes.Get(1), nodes.Get(2));

    NodeContainer n25(nodes.Get(2), nodes.Get(5));

    NodeContainer n03(nodes.Get(0), nodes.Get(3));

    NodeContainer n34(nodes.Get(3), nodes.Get(4));

    NodeContainer n45(nodes.Get(4), nodes.Get(5));

    NodeContainer n24(nodes.Get(2), nodes.Get(4));

 

    NetDeviceContainer d01 = p2p.Install(n01);

    NetDeviceContainer d12 = p2p.Install(n12);

    NetDeviceContainer d25 = p2p.Install(n25);

    NetDeviceContainer d03 = p2p.Install(n03);

    NetDeviceContainer d34 = p2p.Install(n34);

    NetDeviceContainer d45 = p2p.Install(n45);

    NetDeviceContainer d24 = p2p.Install(n24);

 

    MobilityHelper mobility;

    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");

    mobility.Install(nodes);

 

    nodes.Get(0)->GetObject<MobilityModel>()->SetPosition(Vector(10, 30, 0));

    nodes.Get(1)->GetObject<MobilityModel>()->SetPosition(Vector(30, 50, 0));

    nodes.Get(2)->GetObject<MobilityModel>()->SetPosition(Vector(55, 50, 0));

    nodes.Get(3)->GetObject<MobilityModel>()->SetPosition(Vector(30, 10, 0));

    nodes.Get(4)->GetObject<MobilityModel>()->SetPosition(Vector(55, 10, 0));

    nodes.Get(5)->GetObject<MobilityModel>()->SetPosition(Vector(78, 30, 0));

 

    InternetStackHelper internet;

    if (useRip) {

        RipHelper rip;

        Ipv4ListRoutingHelper list;

        list.Add(rip, 10);

        internet.SetRoutingHelper(list);

    } else {

        OlsrHelper olsr;

        Ipv4ListRoutingHelper list;

        list.Add(olsr, 10);

        internet.SetRoutingHelper(list);

    }

    internet.Install(nodes);

 

    Ipv4AddressHelper addr;

    addr.SetBase("10.0.1.0", "255.255.255.0");

    Ipv4InterfaceContainer i01 = addr.Assign(d01);

    addr.SetBase("10.0.2.0", "255.255.255.0");

    addr.Assign(d12);

    addr.SetBase("10.0.3.0", "255.255.255.0");

    Ipv4InterfaceContainer i25 = addr.Assign(d25);

    addr.SetBase("10.0.4.0", "255.255.255.0");

    addr.Assign(d03);

    addr.SetBase("10.0.5.0", "255.255.255.0");

    addr.Assign(d34);

    addr.SetBase("10.0.6.0", "255.255.255.0");

    addr.Assign(d45);

    addr.SetBase("10.0.7.0", "255.255.255.0");

    addr.Assign(d24);

 

    uint16_t port = 9999;

    PacketSinkHelper sinkHelper("ns3::UdpSocketFactory",

        InetSocketAddress(Ipv4Address::GetAny(), port));

    ApplicationContainer sinkApp = sinkHelper.Install(nodes.Get(5));

    sinkApp.Start(Seconds(0.0));

    sinkApp.Stop(Seconds(simTime));

 

    OnOffHelper onoff("ns3::UdpSocketFactory",

        InetSocketAddress(i25.GetAddress(1), port));

    onoff.SetAttribute("DataRate", StringValue("1Mbps"));

    onoff.SetAttribute("PacketSize", UintegerValue(1024));

    onoff.SetAttribute("OnTime",

        StringValue("ns3::ConstantRandomVariable[Constant=1]"));

    onoff.SetAttribute("OffTime",

        StringValue("ns3::ConstantRandomVariable[Constant=0]"));

    ApplicationContainer srcApp = onoff.Install(nodes.Get(0));

    srcApp.Start(Seconds(20.0));

    srcApp.Stop(Seconds(85.0));

 

    Simulator::Schedule(Seconds(40.0), &SetInterfaceDown, nodes.Get(1), d12.Get(0));

    Simulator::Schedule(Seconds(40.0), &SetInterfaceDown, nodes.Get(2), d12.Get(1));

    Simulator::Schedule(Seconds(65.0), &SetInterfaceUp, nodes.Get(1), d12.Get(0));

    Simulator::Schedule(Seconds(65.0), &SetInterfaceUp, nodes.Get(2), d12.Get(1));

 

    std::string animFile = useRip ? "rip.xml" : "olsr.xml";

    AnimationInterface anim(animFile);

    anim.SetConstantPosition(nodes.Get(0), 10, 30);

    anim.SetConstantPosition(nodes.Get(1), 30, 50);

    anim.SetConstantPosition(nodes.Get(2), 55, 50);

    anim.SetConstantPosition(nodes.Get(3), 30, 10);

    anim.SetConstantPosition(nodes.Get(4), 55, 10);

    anim.SetConstantPosition(nodes.Get(5), 78, 30);

    anim.EnablePacketMetadata(true);

    anim.UpdateNodeDescription(nodes.Get(0), "N0 Source");

    anim.UpdateNodeDescription(nodes.Get(1), "N1");

    anim.UpdateNodeDescription(nodes.Get(2), "N2");

    anim.UpdateNodeDescription(nodes.Get(3), "N3");

    anim.UpdateNodeDescription(nodes.Get(4), "N4");

    anim.UpdateNodeDescription(nodes.Get(5), "N5 Destination");

 

    AsciiTraceHelper ascii;

    if (useRip) {

        Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream("rip-routes.txt");

        RipHelper ripHelper;

        ripHelper.PrintRoutingTableAllAt(Seconds(25.0), stream);

        ripHelper.PrintRoutingTableAllAt(Seconds(45.0), stream);

        ripHelper.PrintRoutingTableAllAt(Seconds(70.0), stream);

    } else {

        Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream("olsr-routes.txt");

        OlsrHelper olsrHelper;

        olsrHelper.PrintRoutingTableAllAt(Seconds(25.0), stream);

        olsrHelper.PrintRoutingTableAllAt(Seconds(45.0), stream);

        olsrHelper.PrintRoutingTableAllAt(Seconds(70.0), stream);

    }

 

    if (enablePcap) {

        p2p.EnablePcapAll(useRip ? "rip" : "olsr");

    }

 

    FlowMonitorHelper flowmon;

    Ptr<FlowMonitor> monitor = flowmon.InstallAll();

 

    g_sink = DynamicCast<PacketSink>(sinkApp.Get(0));

    std::string csvFile = useRip ? "rip-throughput.csv" : "olsr-throughput.csv";

    g_csv.open(csvFile.c_str());

    g_csv << "Time,ThroughputKbps,TotalRxBytes\n";

    Simulator::Schedule(Seconds(1.0), &TraceThroughput);

 

    Simulator::Stop(Seconds(simTime));

    Simulator::Run();

 

    monitor->CheckForLostPackets();

    Ptr<Ipv4FlowClassifier> classifier =

        DynamicCast<Ipv4FlowClassifier>(flowmon.GetClassifier());

    std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats();

 

    std::cout << "\n=== " << protocol << " RESULTS ===\n";

    for (const auto& flow : stats) {

        Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(flow.first);

        if (t.destinationPort == port) {

            double throughput = flow.second.rxBytes * 8.0 /

                (flow.second.timeLastRxPacket.GetSeconds() -

                 flow.second.timeFirstTxPacket.GetSeconds()) / 1000.0;

            double avgDelayMs = (flow.second.rxPackets > 0) ?

                1000.0 * flow.second.delaySum.GetSeconds() / flow.second.rxPackets : 0.0;

            double pdr = (flow.second.txPackets > 0) ?

                100.0 * flow.second.rxPackets / flow.second.txPackets : 0.0;

            std::cout << "Flow: " << t.sourceAddress << " -> " << t.destinationAddress << "\n";

            std::cout << "Tx Packets: " << flow.second.txPackets << "\n";

            std::cout << "Rx Packets: " << flow.second.rxPackets << "\n";

            std::cout << "Packet Delivery Ratio: " << pdr << " %\n";

            std::cout << "Average Delay: " << avgDelayMs << " ms\n";

            std::cout << "Throughput: " << throughput << " Kbps\n";

            std::cout << "Lost Packets: " << flow.second.lostPackets << "\n\n";

        }

    }

 

    g_csv.close();

    Simulator::Destroy();

    return 0;

}

7. NetAnim Animation Screenshot

The screenshot below is taken at approximately t = 42–50 s, immediately after the N1–N2 link failure at t = 40 s. This moment is chosen because packets must reroute through the lower path N0–N3–N4–N5, making the visual difference between the two protocols most apparent.

RIP Animation (load rip.xml in NetAnim):

Figure 1 — NetAnim visualization of RIP routing. After the N1–N2 link fails at 40 s, packets are rerouted through N0–N3–N4–N5. Packet activity visible on the lower path.

OLSR Animation (load olsr.xml in NetAnim):

Figure 2 — NetAnim visualization of OLSR routing. Because OLSR maintains a global topology map, rerouting is reflected earlier in the animation. The lower path is active faster than in the RIP case.

Animation Observation: The N1–N2 link fails at 40 s. Both protocols eventually reroute through N0–N3–N4–N5. In OLSR, rerouting becomes visible sooner because the protocol uses proactive link-state updates. In RIP, the transition takes longer because route change information propagates hop-by-hop with periodic update intervals and triggered update cooldowns. 

8. Graphs and Analysis

8.1 Throughput Over Time (from CSV — paste your graph here)

Plot rip-throughput.csv and olsr-throughput.csv together. X-axis = Time (s), Y-axis = Throughput (Kbps), with two lines — one for RIP and one for OLSR.

Figure 3 — Throughput comparison. Throughput is stable before t = 40 s. A drop is observed at link failure. OLSR recovers to near-full throughput sooner; RIP shows a longer recovery gap before re-stabilizing after t = 65 s when the link is restored.

8.2 Protocol Comparison — Terminal Results

The following bar/grouped chart is derived directly from the FlowMonitor terminal output collected after running both simulations.

Metric

RIP (Flow 1)

RIP (Flow 2)

 

Tx Packets

3476

1491

 

Rx Packets

2968

1491

 

Packet Delivery Ratio

85.39 %

100 %

 

Average Delay (ms)

11.06 ms

11.06 ms

 

Throughput (Kbps)

384.30 Kbps

1027.1 Kbps

 

Lost Packets

508

0

 

 

Metric

OLSR (Flow 1)

OLSR (Flow 2)

 

Tx Packets

3093

4841

 

Rx Packets

2440

4841

 

Packet Delivery Ratio

78.89 %

100 %

 

Average Delay (ms)

11.06 ms

11.06 ms

 

Throughput (Kbps)

1027.2 Kbps

1027.27 Kbps

 

Lost Packets

653

0

 

 

Table 1 — FlowMonitor statistics for RIP and OLSR. Flow 1 is the primary traffic flow (N0 → N5). Flow 2 represents traffic on an alternate sub-flow. RIP shows higher PDR on Flow 1 but lower throughput, while OLSR achieves near-line-rate throughput after fast route convergence.

8.3 Side-by-Side Summary Table

Metric

RIP

OLSR

Advantage

Routing Type

Distance-Vector

Link-State

Algorithm

Bellman-Ford

Dijkstra

Update Method

Periodic + Triggered

Proactive flooding

OLSR

Convergence Speed

Slower (hop-by-hop)

Faster (global map)

OLSR

PDR Flow 1

85.39 %

78.89 %

RIP

Throughput Flow 1

384.3 Kbps

1027.2 Kbps

OLSR

Throughput Flow 2

1027.1 Kbps

1027.27 Kbps

Comparable

Lost Packets Flow 1

508

653

RIP

Avg Delay

11.06 ms

11.06 ms

Equal

Table 2 — Side-by-side comparison of RIP and OLSR from simulation results.


9. Result Analysis

Before the link failure at t = 40 s, both protocols deliver traffic normally through the upper path N0–N1–N2–N5. Throughput is stable at approximately 1 Mbps for both. When the N1–N2 link is brought down, the routing layer on both sides must detect the failure and install a new route through N0–N3–N4–N5.

RIP detects the failure via timeout or triggered update, but propagates the change hop-by-hop. During this period, packets that arrive at N1 have no valid route to N2 and are dropped, resulting in 508 lost packets on Flow 1 (PDR 85.39%). The throughput on Flow 1 drops significantly to 384.3 Kbps, reflecting the extended period without a valid route. Once convergence occurs, the alternate path carries traffic correctly (Flow 2: 1027.1 Kbps, 100% PDR).

OLSR, being proactive, already has topology knowledge from Hello and TC messages. When the link fails, the MPR-based flooding quickly propagates updated topology information, and Dijkstra recomputes routes. Despite this, OLSR's Flow 1 has a slightly lower PDR (78.89%) and higher packet loss (653 packets), which may be attributed to OLSR's hello interval timing and the initial topology-build phase. Flow 2 achieves near line-rate throughput (1027.27 Kbps) with perfect delivery.

Average end-to-end delay is equal for both protocols (11.06 ms), which is expected since link delays are identical and both protocols eventually route through the same 3-hop path. The main differentiator in this experiment is throughput recovery speed, where OLSR's Flow 2 shows superior per-flow throughput after rerouting.

10. Conclusion

This experiment successfully demonstrates the behavioural difference between Distance-Vector (RIP) and Link-State (OLSR) routing protocols under a topology change. The ns-3 simulation with NetAnim visualization confirms that both protocols can adapt to link failures. However, OLSR achieves higher peak throughput on the surviving flow due to faster topology awareness. RIP achieves a slightly better PDR on the primary flow in this specific scenario but at a significantly lower throughput due to prolonged convergence delay.

In practical terms, link-state protocols are preferred in networks where rapid convergence after failure is critical. Distance-vector protocols remain simpler to implement and suitable for small, stable networks. This comparison validates the theoretical claims about protocol behavior and demonstrates the utility of ns-3 and NetAnim as simulation and visualization tools.

Comments

Popular posts from this blog

How to Create Ubuntu 24.04 Bootable USB Using Rufus [Step-by-Step Guide]

How to Create Ubuntu 24.04 Bootable USB Using Rufus [Step-by-Step Guide] Are you planning to install or try Ubuntu 24.04 LTS ? The easiest and most reliable method is to create a bootable USB drive using Rufus on a Windows system. This detailed guide will help you create a Ubuntu 24.04 USB bootloader using Rufus with easy-to-follow steps and screenshots (optional). Here is the complete video of the bootloader creation and OS installation in Windows 11. 🧰 Requirements A USB flash drive (minimum 8GB recommended) A Windows PC Ubuntu 24.04 LTS ISO file Rufus USB creation tool 🧾 Steps to Create a Ubuntu 24.04 Bootable USB Using Rufus ✅ Step 1: Download Ubuntu 24.04 ISO Visit the official Ubuntu website and download the Ubuntu 24.04 LTS ISO file . ✅ Step 2: Download and Run Rufus Head to Rufus official site and download the latest version. Open the executable file (no installation required). ✅ Step 3: Insert USB Drive Plug in your USB drive. Rufus ...

Installing ns3 in Ubuntu 22.04 | Complete Instructions

In this post, we are going to see how to install ns-3.36.1 in Ubuntu 22.04. You can follow the video for complete details Tools used in this simulation: NS3 version ns-3.36.1  OS Used: Ubuntu 22.04 LTS Installation of NS3 (ns-3.36.1) There are some changes in the ns3 installation procedure and the dependencies. So open a terminal and issue the following commands Step 1:  Prerequisites $ sudo apt update In the following packages, all the required dependencies are taken care and you can install all these packages for the complete use of ns3. $ sudo apt install g++ python3 python3-dev pkg-config sqlite3 cmake python3-setuptools git qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3 openmpi-bin openmpi-common openmpi-doc libopenmpi-dev autoconf cvs bzr unrar gsl-bin libgsl-dev libgslcblas0 wireshark tcpdump sqlite sqlite3 libsqlite3-dev  libxml2 libxml2-dev libc6-dev libc6-dev-i386 libc...

Installation of NS2 in Ubuntu 22.04 | NS2 Tutorial 2

NS-2.35 installation in Ubuntu 22.04 This post shows how to install ns-2.35 in Ubuntu 22.04 Operating System Since ns-2.35 is too old, it needs the following packages gcc-4.8 g++-4.8 gawk and some more libraries Follow the video for more instructions So, here are the steps to install this software: To download and extract the ns2 software Download the software from the following link http://sourceforge.net/projects/nsnam/files/allinone/ns-allinone-2.35/ns-allinone-2.35.tar.gz/download Extract it to home folder and in my case its /home/pradeepkumar (I recommend to install it under your home folder) $ tar zxvf ns-allinone-2.35.tar.gz or Right click over the file and click extract here and select the home folder. $ sudo apt update $ sudo apt install build-essential autoconf automake libxmu-dev gawk To install gcc-4.8 and g++-4.8 $ sudo gedit /etc/apt/sources.list make an entry in the above file deb http://in.archive.ubuntu.com/ubuntu/ bionic main universe $ sudo apt update Since, it...