/* * Copyright (c) 2013 Universita' di Firenze * Copyright (c) 2019 Caliola Engineering, LLC : RFC 6621 multicast packet de-duplication * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Tommaso Pecorella * Modified (2019): Jared Dulmage * Demonstrates dissemination of multicast packets across a mesh * network to all nodes over multiple hops. */ #include "ns3/boolean.h" #include "ns3/config.h" #include "ns3/data-rate.h" #include "ns3/double.h" #include "ns3/inet-socket-address.h" #include "ns3/internet-stack-helper.h" #include "ns3/ipv4-address-helper.h" #include "ns3/ipv4-l3-protocol.h" #include "ns3/ipv4-list-routing-helper.h" #include "ns3/ipv4-static-routing-helper.h" #include "ns3/ipv4-static-routing.h" #include "ns3/log.h" #include "ns3/names.h" #include "ns3/node.h" #include "ns3/on-off-helper.h" #include "ns3/packet-sink-helper.h" #include "ns3/packet-sink.h" #include "ns3/random-variable-stream.h" #include "ns3/simple-channel.h" #include "ns3/simple-net-device-helper.h" #include "ns3/simple-net-device.h" #include "ns3/simulator.h" #include "ns3/socket.h" #include "ns3/string.h" #include "ns3/test.h" #include "ns3/trace-helper.h" #include "ns3/traffic-control-layer.h" #include "ns3/udp-socket-factory.h" #include "ns3/udp-socket.h" #include "ns3/uinteger.h" #include #include #include using namespace ns3; /** * Network topology: * * /---- B ----\ * A ---- | ---- D ---- E * \---- C ----/ * * This example demonstrates configuration of * static routing to realize broadcast-like * flooding of packets from node A * across the illustrated topology. */ int main(int argc, char* argv[]) { // multicast target const std::string targetAddr = "239.192.100.1"; Config::SetDefault("ns3::Ipv4L3Protocol::EnableDuplicatePacketDetection", BooleanValue(true)); Config::SetDefault("ns3::Ipv4L3Protocol::DuplicateExpire", TimeValue(Seconds(10))); // Create topology // Create nodes auto nodes = NodeContainer(); nodes.Create(5); // Name nodes Names::Add("A", nodes.Get(0)); Names::Add("B", nodes.Get(1)); Names::Add("C", nodes.Get(2)); Names::Add("D", nodes.Get(3)); Names::Add("E", nodes.Get(4)); SimpleNetDeviceHelper simplenet; auto devices = simplenet.Install(nodes); // name devices Names::Add("A/dev", devices.Get(0)); Names::Add("B/dev", devices.Get(1)); Names::Add("C/dev", devices.Get(2)); Names::Add("D/dev", devices.Get(3)); Names::Add("E/dev", devices.Get(4)); // setup static routes to facilitate multicast flood Ipv4ListRoutingHelper listRouting; Ipv4StaticRoutingHelper staticRouting; listRouting.Add(staticRouting, 0); InternetStackHelper internet; internet.SetIpv6StackInstall(false); internet.SetIpv4ArpJitter(true); internet.SetRoutingHelper(listRouting); internet.Install(nodes); Ipv4AddressHelper ipv4address; ipv4address.SetBase("10.0.0.0", "255.255.255.0"); ipv4address.Assign(devices); // add static routes for each node / device for (auto diter = devices.Begin(); diter != devices.End(); ++diter) { Ptr node = (*diter)->GetNode(); if (Names::FindName(node) == "A") { // route for host // Use host routing entry according to note in Ipv4StaticRouting::RouteOutput: //// Note: Multicast routes for outbound packets are stored in the //// normal unicast table. An implication of this is that it is not //// possible to source multicast datagrams on multiple interfaces. //// This is a well-known property of sockets implementation on //// many Unix variants. //// So, we just log it and fall through to LookupStatic () auto ipv4 = node->GetObject(); NS_ASSERT_MSG((bool)ipv4, "Node " << Names::FindName(node) << " does not have Ipv4 aggregate"); auto routing = staticRouting.GetStaticRouting(ipv4); routing->AddHostRouteTo(targetAddr.c_str(), ipv4->GetInterfaceForDevice(*diter), 0); } else { // route for forwarding staticRouting.AddMulticastRoute(node, Ipv4Address::GetAny(), targetAddr.c_str(), *diter, NetDeviceContainer(*diter)); } } // set the topology, by default fully-connected auto channel = devices.Get(0)->GetChannel(); auto simplechannel = channel->GetObject(); simplechannel->BlackList(Names::Find("A/dev"), Names::Find("D/dev")); simplechannel->BlackList(Names::Find("D/dev"), Names::Find("A/dev")); simplechannel->BlackList(Names::Find("A/dev"), Names::Find("E/dev")); simplechannel->BlackList(Names::Find("E/dev"), Names::Find("A/dev")); simplechannel->BlackList(Names::Find("B/dev"), Names::Find("E/dev")); simplechannel->BlackList(Names::Find("E/dev"), Names::Find("B/dev")); simplechannel->BlackList(Names::Find("C/dev"), Names::Find("E/dev")); simplechannel->BlackList(Names::Find("E/dev"), Names::Find("C/dev")); // ensure some time progress between re-transmissions simplechannel->SetAttribute("Delay", TimeValue(MilliSeconds(1))); // sinks PacketSinkHelper sinkHelper("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), 9)); auto sinks = sinkHelper.Install("B"); sinks.Add(sinkHelper.Install("C")); sinks.Add(sinkHelper.Install("D")); sinks.Add(sinkHelper.Install("E")); sinks.Start(Seconds(1)); // source OnOffHelper onoffHelper("ns3::UdpSocketFactory", InetSocketAddress(targetAddr.c_str(), 9)); onoffHelper.SetAttribute("DataRate", DataRateValue(DataRate("8Mbps"))); onoffHelper.SetAttribute("MaxBytes", UintegerValue(10 * 1024)); auto source = onoffHelper.Install("A"); source.Start(Seconds(1.1)); // pcap traces for (auto end = nodes.End(), iter = nodes.Begin(); iter != end; ++iter) { internet.EnablePcapIpv4("smf-trace", (*iter)->GetId(), 1, false); } // run simulation Simulator::Run(); std::cout << "Node A sent " << 10 * 1024 << " bytes" << std::endl; for (auto end = sinks.End(), iter = sinks.Begin(); iter != end; ++iter) { auto node = (*iter)->GetNode(); auto sink = (*iter)->GetObject(); std::cout << "Node " << Names::FindName(node) << " received " << sink->GetTotalRx() << " bytes" << std::endl; } Simulator::Destroy(); Names::Clear(); return 0; }