Fix for bug69: set local address correctly upon UDP connect; apply correct UDP connect() semantics (that sendto cannot override addresses on a connected socket); if destination is IPv4 limited broadcast address, convert to subnet-directed broadcast and send out on each interface; provide example csma-broadcast.cc script
This commit is contained in:
159
examples/csma-broadcast.cc
Normal file
159
examples/csma-broadcast.cc
Normal file
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
//
|
||||
// Example of the sending of a datagram to a broadcast address
|
||||
//
|
||||
// Network topology
|
||||
// ==============
|
||||
// | |
|
||||
// n0 n1 n2
|
||||
// | |
|
||||
// ==========
|
||||
//
|
||||
// n0 originates UDP broadcast to 255.255.255.255, which is replicated
|
||||
// and received on both n1 and n2
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/debug.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/eui48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
DebugComponentEnable("CsmaNetDevice");
|
||||
DebugComponentEnable("Ipv4L3Protocol");
|
||||
DebugComponentEnable("NetDevice");
|
||||
DebugComponentEnable("Channel");
|
||||
DebugComponentEnable("CsmaChannel");
|
||||
DebugComponentEnable("PacketSocket");
|
||||
#endif
|
||||
|
||||
// Set up some default values for the simulation. Use the Bind()
|
||||
// technique to tell the system what subclass of Queue to use,
|
||||
// and what the queue limit is
|
||||
|
||||
// The below Bind command tells the queue factory which class to
|
||||
// instantiate, when the queue factory is invoked in the topology code
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<CsmaChannel> channel0 =
|
||||
CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<CsmaChannel> channel1 =
|
||||
CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0,
|
||||
Eui48Address("10:54:23:54:0:50"));
|
||||
uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel1,
|
||||
Eui48Address("10:54:23:54:0:51"));
|
||||
uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
|
||||
Eui48Address("10:54:23:54:23:51"));
|
||||
uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel1,
|
||||
Eui48Address("10:54:23:54:23:52"));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n0, n0ifIndex0, Ipv4Address("10.1.0.1"), Ipv4Mask("255.255.0.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n1, n1ifIndex, Ipv4Address("10.1.0.2"), Ipv4Mask("255.255.0.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n0, n0ifIndex1, Ipv4Address("192.168.1.1"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
// from n0 to n1
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("255.255.255.255", 80),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the csma-broadcast.tr file
|
||||
AsciiTrace asciitrace ("csma-broadcast.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-point-to-point.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("csma-broadcast.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -14,6 +14,10 @@ def build(bld):
|
||||
['csma', 'internet-node'])
|
||||
obj.source = 'csma-one-subnet.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-broadcast',
|
||||
['csma', 'internet-node'])
|
||||
obj.source = 'csma-broadcast.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-packet-socket',
|
||||
['csma', 'internet-node'])
|
||||
obj.source = 'csma-packet-socket.cc'
|
||||
|
||||
@@ -62,8 +62,9 @@ ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
|
||||
Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
|
||||
Address hardwareDestination;
|
||||
bool found;
|
||||
|
||||
if (dest.IsBroadcast ())
|
||||
|
||||
if (dest.IsBroadcast () ||
|
||||
dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
|
||||
{
|
||||
hardwareDestination = GetDevice ()->GetBroadcast ();
|
||||
found = true;
|
||||
|
||||
@@ -153,10 +153,6 @@ UdpSocket::Connect(const Address & address)
|
||||
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
||||
m_defaultAddress = transport.GetIpv4 ();
|
||||
m_defaultPort = transport.GetPort ();
|
||||
if (m_defaultAddress.IsBroadcast () )
|
||||
{
|
||||
NS_ASSERT_MSG(false, "UdpSocket::Connect, can't connect to broadcast");
|
||||
}
|
||||
NotifyConnectionSucceeded ();
|
||||
m_connected = true;
|
||||
if (GetIpv4RouteToDestination (m_node, routeToDest, m_defaultAddress) )
|
||||
@@ -196,24 +192,31 @@ UdpSocket::DoSend (const Packet &p)
|
||||
m_errno = ERROR_SHUTDOWN;
|
||||
return -1;
|
||||
}
|
||||
m_udp->Send (p, m_endPoint->GetLocalAddress (), m_defaultAddress,
|
||||
m_endPoint->GetLocalPort (), m_defaultPort);
|
||||
NotifyDataSent (p.GetSize ());
|
||||
return 0;
|
||||
|
||||
return DoSendTo (p, m_defaultAddress, m_defaultPort);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UdpSocket::DoSendTo (const Packet &p, const Address &address)
|
||||
{
|
||||
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
||||
Ipv4Address ipv4 = transport.GetIpv4 ();
|
||||
uint16_t port = transport.GetPort ();
|
||||
return DoSendTo (p, ipv4, port);
|
||||
if (!m_connected)
|
||||
{
|
||||
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
||||
Ipv4Address ipv4 = transport.GetIpv4 ();
|
||||
uint16_t port = transport.GetPort ();
|
||||
return DoSendTo (p, ipv4, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
// connected UDP socket must use default addresses
|
||||
return DoSendTo (p, m_defaultAddress, m_defaultPort);
|
||||
}
|
||||
}
|
||||
int
|
||||
UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
|
||||
{
|
||||
Ipv4Route routeToDest;
|
||||
if (m_endPoint == 0)
|
||||
{
|
||||
if (Bind () == -1)
|
||||
@@ -228,8 +231,23 @@ UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
|
||||
m_errno = ERROR_SHUTDOWN;
|
||||
return -1;
|
||||
}
|
||||
Ipv4Route routeToDest;
|
||||
if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
|
||||
//
|
||||
// If dest is sent to the limited broadcast address (all ones),
|
||||
// convert it to send a copy of the packet out of every interface
|
||||
//
|
||||
if (dest.IsBroadcast ())
|
||||
{
|
||||
Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
|
||||
{
|
||||
Ipv4Address addri = ipv4->GetAddress (i);
|
||||
Ipv4Mask maski = ipv4->GetNetworkMask (i);
|
||||
m_udp->Send (p, addri, addri.GetSubnetDirectedBroadcast (maski),
|
||||
m_endPoint->GetLocalPort (), port);
|
||||
NotifyDataSent (p.GetSize ());
|
||||
}
|
||||
}
|
||||
else if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
|
||||
{
|
||||
uint32_t localIfIndex = routeToDest.GetInterface ();
|
||||
Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
|
||||
@@ -99,6 +99,11 @@ Ipv4Mask::SetHostOrder (uint32_t value)
|
||||
{
|
||||
m_mask = value;
|
||||
}
|
||||
uint32_t
|
||||
Ipv4Mask::GetInverse (void) const
|
||||
{
|
||||
return ~m_mask;
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4Mask::Print (std::ostream &os) const
|
||||
@@ -162,6 +167,18 @@ Ipv4Address::CombineMask (Ipv4Mask const &mask) const
|
||||
return Ipv4Address (GetHostOrder () & mask.GetHostOrder ());
|
||||
}
|
||||
|
||||
Ipv4Address
|
||||
Ipv4Address::GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const
|
||||
{
|
||||
return Ipv4Address (GetHostOrder () | mask.GetInverse ());
|
||||
}
|
||||
|
||||
bool
|
||||
Ipv4Address::IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const
|
||||
{
|
||||
return ( (GetHostOrder () | mask.GetInverse ()) == GetHostOrder () );
|
||||
}
|
||||
|
||||
bool
|
||||
Ipv4Address::IsBroadcast (void) const
|
||||
{
|
||||
|
||||
@@ -119,6 +119,16 @@ public:
|
||||
* \param mask a network mask
|
||||
*/
|
||||
Ipv4Address CombineMask (Ipv4Mask const &mask) const;
|
||||
/**
|
||||
* \brief Generate subnet-directed broadcast address corresponding to mask
|
||||
*
|
||||
* The subnet-directed broadcast address has the host bits set to all
|
||||
* ones.
|
||||
*
|
||||
* \param mask a network mask
|
||||
*/
|
||||
Ipv4Address GetSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
|
||||
bool IsSubnetDirectedBroadcast (Ipv4Mask const &mask) const;
|
||||
|
||||
static bool IsMatchingType (const Address &address);
|
||||
operator Address ();
|
||||
@@ -151,6 +161,10 @@ public:
|
||||
*/
|
||||
uint32_t GetHostOrder (void) const;
|
||||
void SetHostOrder (uint32_t value);
|
||||
/**
|
||||
* \brief Return the inverse mask in host order.
|
||||
*/
|
||||
uint32_t GetInverse (void) const;
|
||||
|
||||
void Print (std::ostream &os) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user