From 929e23b74e247b58429ae2f844de86a04299f0a0 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 4 Sep 2007 21:26:54 -0700 Subject: [PATCH] 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 --- examples/csma-broadcast.cc | 159 ++++++++++++++++++++++++ examples/wscript | 4 + src/internet-node/arp-ipv4-interface.cc | 5 +- src/internet-node/udp-socket.cc | 46 ++++--- src/node/ipv4-address.cc | 17 +++ src/node/ipv4-address.h | 14 +++ 6 files changed, 229 insertions(+), 16 deletions(-) create mode 100644 examples/csma-broadcast.cc diff --git a/examples/csma-broadcast.cc b/examples/csma-broadcast.cc new file mode 100644 index 000000000..1cb9faa75 --- /dev/null +++ b/examples/csma-broadcast.cc @@ -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 +#include +#include +#include + +#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 n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + CsmaTopology::CreateCsmaChannel( + DataRate(5000000), MilliSeconds(2)); + + // We create the channels first without any IP addressing information + Ptr 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 ooff = Create ( + 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-- + // 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 (); +} diff --git a/examples/wscript b/examples/wscript index e5e771555..56c8797b6 100644 --- a/examples/wscript +++ b/examples/wscript @@ -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' diff --git a/src/internet-node/arp-ipv4-interface.cc b/src/internet-node/arp-ipv4-interface.cc index efe767531..17960c3f7 100644 --- a/src/internet-node/arp-ipv4-interface.cc +++ b/src/internet-node/arp-ipv4-interface.cc @@ -62,8 +62,9 @@ ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest) Ptr arp = m_node->QueryInterface (ArpL3Protocol::iid); Address hardwareDestination; bool found; - - if (dest.IsBroadcast ()) + + if (dest.IsBroadcast () || + dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) ) { hardwareDestination = GetDevice ()->GetBroadcast (); found = true; diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index a9b063a2c..39fd39ddb 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -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 = m_node->QueryInterface (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 = m_node->QueryInterface (Ipv4::iid); diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 4e1e344c5..0b0a48f29 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -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 { diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index 6589edcf9..f473b57c0 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -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;