diff --git a/src/routing/click/doc/click.h b/src/routing/click/doc/click.h new file mode 100644 index 000000000..c21230de3 --- /dev/null +++ b/src/routing/click/doc/click.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2010 Lalith Suresh + * + * 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 + * + * Authors: Lalith Suresh + */ + +/** +* \ingroup routing +* \defgroup click Click +* +* \section model Model +* +* This model implements the interface to the Click Modular Router and +* provides the Ipv4ClickRouting class to allow a node to use Click +* for external routing. Unlike normal Ipv4RoutingProtocol sub types, +* Ipv4ClickRouting doesn't use a RouteInput() method, but instead, +* receives a packet on the appropriate interface and processes it +* accordingly. Note that you need to have a routing table type element +* in your Click graph to use Click for external routing. This is needed +* by the RouteOutput() function inherited from Ipv4RoutingProtocol. +* Furthermore, a Click based node uses a different kind of L3 in the +* form of Ipv4L3ClickProtocol, which is a trimmed down version of +* Ipv4L3Protocol. Ipv4L3ClickProtocol passes on packets passing through +* the stack to Ipv4ClickRouting for processing. +* +* \section build Build Instructions +* +* The first step is to build Click. At the top of your Click source directory: +* +* $: ./configure --enable-userlevel --disable-linuxmodule --enable-nsclick --enable-wifi +* $: make +* +* The --enable wifi flag can be skipped in case you don't intend on using +* Click with Wifi. +* *Note: You don't need to do a 'make install'. +* +* Once Click has been built successfully, we proceed to configure ns-3 with +* Click Integration support: +* +* $: ./waf configure --with-nsclick=/path/to/click/source +* +* If it says 'enabled' beside 'NS-3 Click Integration Support', then you're +* good to go. +* +* Next, try running one of the examples: +* +* $: ./waf --run nsclick-simple-lan +* +* You will find a lot of output being generated. This is because of the +* IPPrint and Print elements present in the nsclick-simple-lan.click +* configuration file that the example script uses. +* +* \section clickgraph Click Graph Instructions +* +* The following should be kept in mind when making your Click graph: +* - Only userlevel elements can be used. +* - You will need to replace FromDevice and ToDevice elements +* with FromSimDevice and ToSimDevice elements. +* - Packets to the kernel are sent up using ToSimDevice(tap0,IP). +* - For any node, the 0th device will be tap0. The remaining devices +* should be eth0, eth1 and so forth (even if you're using wifi). +* Please note that the device numbering should begin from 0. +* - A routing table element is a mandatory. The OUTports of the routing +* table element should correspond to the interface number of the device +* through which the packet will ultimately be sent out. Violating this +* rule will lead to really weird packet traces. This routing table element's +* name should then be passed to the Ipv4ClickRouting protocol object as +* a simulation parameter. See the Click examples for details. +* - When using Wifi with ns-3-click, do not use wifi specific elements like +* WifiEncap, ExtraEncap, MadWifiRate etc. for outgoing packets. Incoming +* packets should have their Wifi headers removed using WifiDecap + ExtraDecap +* or Strip elements. See the nsclick-raw-wlan.click file for an idea of the same. +* - The current implementation leaves Click with mainly L3 functionality, +* with ns-3 handling L2. We will soon begin working to support the use of +* MAC protocols on Click as well. +* +* \section usage Usage +* +* To have a node run Click, the easiest way would be to use the ClickInternetStackHelper +* class in your simulation script. For instance: +* +* ClickInternetStackHelper click; +* click.SetClickFile (myNodeContainer, "nsclick-simple-lan.click"); +* click.SetRoutingTableElement (myNodeContainer, "u/rt"); +* click.Install (myNodeContainer); +* +* The example scripts inside examples/click/ demonstrate the use of Click based +* nodes in different scenarios. +* +* +*/ + diff --git a/src/routing/click/examples/nsclick-ip-router.click b/src/routing/click/examples/nsclick-ip-router.click new file mode 100644 index 000000000..9d4586fbb --- /dev/null +++ b/src/routing/click/examples/nsclick-ip-router.click @@ -0,0 +1,82 @@ +// Generated by make-ip-conf.pl +// eth0 172.16.1.2 00:00:00:00:00:02 +// eth1 172.16.2.1 00:00:00:00:00:03 + +elementclass IPRouter { + $myaddr1, $myaddr_ethernet1, $myaddr2, $myaddr_ethernet2 | + +// Shared IP input path and routing table +ip :: Strip(14) + -> CheckIPHeader2(INTERFACES 172.16.1.2/255.255.255.0 172.16.2.1/255.255.255.0) + -> rt :: StaticIPLookup( + 172.16.1.2/32 0, + 172.16.1.255/32 0, + 172.16.1.0/32 0, + 172.16.2.1/32 0, + 172.16.2.255/32 0, + 172.16.2.0/32 0, + 172.16.1.0/255.255.255.0 1, + 172.16.2.0/255.255.255.0 2, + 255.255.255.255/32 0.0.0.0 0, + 0.0.0.0/32 0, + 0.0.0.0/0.0.0.0 18.26.4.1 1); + +// ARP responses are copied to each ARPQuerier and the host. +arpt :: Tee(3); + +// Input and output paths for eth0 +c0 :: Classifier(12/0806 20/0001, 12/0806 20/0002, 12/0800, -); +FromSimDevice(eth0, 4096) -> c0; +out0 :: Queue(200) -> todevice0 :: ToSimDevice(eth0); +c0[0] -> ar0 :: ARPResponder(eth0) -> out0; +arpq0 :: ARPQuerier(eth0) -> out0; +c0[1] -> arpt; +arpt[0] -> [1]arpq0; +c0[2] -> Paint(1) -> ip; +c0[3] -> Discard; + +// Input and output paths for eth1 +c1 :: Classifier(12/0806 20/0001, 12/0806 20/0002, 12/0800, -); +FromSimDevice(eth1, 4096) -> c1; +out1 :: Queue(200) -> todevice1 :: ToSimDevice(eth1); +c1[0] -> ar1 :: ARPResponder(eth0) -> out1; +arpq1 :: ARPQuerier(eth1) -> out1; +c1[1] -> arpt; +arpt[1] -> [1]arpq1; +c1[2] -> Paint(2) -> ip; +c1[3] -> Discard; + +// Local delivery +//toh :: ToSimDevice(tap0,IP); +arpt[2] -> Discard; +rt[0] -> Discard; + +// Forwarding path for eth0 +rt[1] -> DropBroadcasts + -> cp0 :: PaintTee(1) + -> gio0 :: IPGWOptions($myaddr1) + -> FixIPSrc($myaddr1) + -> dt0 :: DecIPTTL + -> fr0 :: IPFragmenter(1500) + -> [0]arpq0; +dt0[1] -> ICMPError($myaddr1, timeexceeded) -> rt; +fr0[1] -> ICMPError($myaddr1, unreachable, needfrag) -> rt; +gio0[1] -> ICMPError($myaddr1, parameterproblem) -> rt; +cp0[1] -> ICMPError($myaddr1, redirect, host) -> rt; + +// Forwarding path for eth1 +rt[2] -> DropBroadcasts + -> cp1 :: PaintTee(2) + -> gio1 :: IPGWOptions($myaddr2) + -> FixIPSrc($myaddr2) + -> dt1 :: DecIPTTL + -> fr1 :: IPFragmenter(1500) + -> [0]arpq1; +dt1[1] -> ICMPError($myaddr2, timeexceeded) -> rt; +fr1[1] -> ICMPError($myaddr2, unreachable, needfrag) -> rt; +gio1[1] -> ICMPError($myaddr2, parameterproblem) -> rt; +cp1[1] -> ICMPError($myaddr2, redirect, host) -> rt; + +} + +u :: IPRouter(eth0,eth0,eth1,eth1); diff --git a/src/routing/click/examples/nsclick-lan-single-interface.click b/src/routing/click/examples/nsclick-lan-single-interface.click new file mode 100644 index 000000000..0e3af16b3 --- /dev/null +++ b/src/routing/click/examples/nsclick-lan-single-interface.click @@ -0,0 +1,113 @@ +// nsclick-lan-single-interface.click +// +// Copyright (c) 2011, Deutsche Telekom Laboratories +// +// 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: Ruben Merz +// +// This is a single host Click configuration for a LAN. +// The node broadcasts ARP requests if it wants to find a destination +// address, and it responds to ARP requests made for it. + +elementclass LanSimHost { + $ipaddr, $hwaddr | + + cl::Classifier(12/0806 20/0001,12/0806 20/0002, -); + forhost::IPClassifier(dst host $ipaddr,-); + arpquerier::ARPQuerier(eth0); + arpresponder::ARPResponder(eth0); + + ethout::Queue + -> ToDump(out_eth0.pcap,PER_NODE 1) + -> ToSimDevice(eth0); + + // All packets received on eth0 are silently + // dropped if they are destined for another location + FromSimDevice(eth0,4096) + -> ToDump(in_eth0.pcap,PER_NODE 1,ENCAP ETHER) + -> cl; + + // ARP queries from other nodes go to the ARP responder element + cl[0] -> arpresponder; + + // ARP responses go to our ARP query element + cl[1] -> [1]arpquerier; + + // All other packets get checked whether they are meant for us + cl[2] + -> Strip(14) + -> CheckIPHeader2 + -> MarkIPHeader + -> GetIPAddress(16) // Sets destination IP address annotation from packet data + -> forhost; + + // Packets for us are pushed outside + forhost[0] + ->[0]output; + + // Packets for other folks or broadcast packets get sent to output 1 + forhost[1] + -> ToDump(discard.pcap,2000,PER_NODE 1,ENCAP IP) + -> [1]output; + + // Incoming packets get pushed into the ARP query module + input[0] + -> arpquerier; + + // Both the ARP query and response modules send data out to + // the simulated network device, eth0. + arpquerier + -> ToDump(out_arpquery.pcap,PER_NODE 1) + -> ethout; + + arpresponder + -> ToDump(out_arprespond.pcap,PER_NODE 1) + -> ethout; + +} + +elementclass TapSimHost { + $dev | + + // Packets go to "tap0" which sends them to the kernel + input[0] + -> ToDump(tokernel.pcap,2000,IP,PER_NODE 1) + -> ToSimDevice($dev,IP); + + // Packets sent out by the "kernel" get pushed outside + FromSimDevice($dev,4096) + -> CheckIPHeader2 + -> ToDump(fromkernel.pcap,2000,IP,PER_NODE 1) + -> GetIPAddress(16) + -> [0]output; +} + +// Instantiate elements +lan::LanSimHost(eth0:ip,eth0:eth); +kernel::TapSimHost(tap0); + +// Users can do some processing between the two elements +lan[0] -> kernel; +kernel -> lan; +// Packets for others or broadcasts are discarded +lan[1] -> Discard; + +// It is mandatory to use an IPRouteTable element with ns-3-click +// (but we do not use it in this example) +rt :: LinearIPLookup (172.16.1.0/24 0.0.0.0 1); +// We are actually not using the routing table +Idle () -> rt; +rt[0] -> Discard; +rt[1] -> Discard; diff --git a/src/routing/click/examples/nsclick-raw-wlan.cc b/src/routing/click/examples/nsclick-raw-wlan.cc new file mode 100644 index 000000000..a2171a654 --- /dev/null +++ b/src/routing/click/examples/nsclick-raw-wlan.cc @@ -0,0 +1,142 @@ +/* -*- 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 + * + * Authors: Lalith Suresh + */ + +// Scenario: node A (using Click) sends packets to node B (not using +// Click) +// +// (Click) (non-Click) +// A ))) WLAN ((( B +// (172.16.1.1) (172.16.1.2) +// (eth0) +// + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/helper-module.h" +#include "ns3/click-internet-stack-helper.h" +#include "ns3/log.h" + +using namespace ns3; + +void ReceivePacket (Ptr socket) +{ + NS_LOG_UNCOND ("Received one packet!"); +} + +int main (int argc, char *argv[]) +{ +#ifdef NS3_CLICK + double rss = -80; + Time interPacketInterval = Seconds(1.0); + + // Setup nodes + NodeContainer wifiNodes; + wifiNodes.Create (2); + + // Get Wifi devices installed on both nodes. + // Adapted from examples/wireless/wifi-simple-adhoc.cc + std::string phyMode ("DsssRate1Mbps"); + + // disable fragmentation for frames below 2200 bytes + Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200")); + // turn off RTS/CTS for frames below 2200 bytes + Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200")); + // Fix non-unicast data rate to be the same as that of unicast + Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", + StringValue (phyMode)); + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211b); + + YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default (); + // This is one parameter that matters when using FixedRssLossModel + // set it to zero; otherwise, gain will be added + wifiPhy.Set ("RxGain", DoubleValue (0) ); + // ns-3 supports RadioTap and Prism tracing extensions for 802.11b + wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO); + + YansWifiChannelHelper wifiChannel ; + wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel"); + // The below FixedRssLossModel will cause the rss to be fixed regardless + // of the distance between the two stations, and the transmit power + wifiChannel.AddPropagationLoss ("ns3::FixedRssLossModel","Rss",DoubleValue(rss)); + wifiPhy.SetChannel (wifiChannel.Create ()); + + // Add a non-QoS upper mac, and disable rate control + NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default (); + wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode",StringValue(phyMode), + "ControlMode",StringValue(phyMode)); + // Set it to adhoc mode + wifiMac.SetType ("ns3::AdhocWifiMac"); + NetDeviceContainer wifiDevices = wifi.Install (wifiPhy, wifiMac, wifiNodes); + + // Setup mobility models + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (5.0, 0.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiNodes); + + // Install normal internet stack on node B + InternetStackHelper internet; + internet.Install (wifiNodes.Get (1)); + + // Install Click on node A + ClickInternetStackHelper clickinternet; + clickinternet.SetClickFile (wifiNodes.Get (0), "src/routing/click/examples/nsclick-wifi-single-interface.click"); + clickinternet.SetRoutingTableElement(wifiNodes.Get (0), "rt"); + clickinternet.Install (wifiNodes.Get (0)); + + // Configure IP addresses + Ipv4AddressHelper ipv4; + ipv4.SetBase ("172.16.1.0", "255.255.255.0"); + ipv4.Assign (wifiDevices); + + // Setup traffic application and sockets + Address LocalAddress (InetSocketAddress (Ipv4Address::GetAny (), 50000)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", LocalAddress); + ApplicationContainer recvapp = packetSinkHelper.Install (wifiNodes.Get (1)); + recvapp.Start (Seconds (5.0)); + recvapp.Stop (Seconds (10.0)); + + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); + onOffHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onOffHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer appcont; + + AddressValue remoteAddress (InetSocketAddress (Ipv4Address ("172.16.1.2"), 50000)); + onOffHelper.SetAttribute ("Remote", remoteAddress); + appcont.Add (onOffHelper.Install (wifiNodes.Get (0))); + + appcont.Start (Seconds (5.0)); + appcont.Stop (Seconds (10.0)); + + // For tracing + wifiPhy.EnablePcap ("nsclick-raw-wlan", wifiDevices); + + Simulator::Stop (Seconds(20.0)); + Simulator::Run(); + return 0; +#else + NS_FATAL_ERROR ("Can't use ns-3-click without NSCLICK compiled in"); +#endif +} diff --git a/src/routing/click/examples/nsclick-routing-node0.click b/src/routing/click/examples/nsclick-routing-node0.click new file mode 100644 index 000000000..7e855d813 --- /dev/null +++ b/src/routing/click/examples/nsclick-routing-node0.click @@ -0,0 +1,112 @@ +// nsclick-lan-single-interface.click +// +// Copyright (c) 2011, Deutsche Telekom Laboratories +// +// 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: Ruben Merz +// +// This is a single host Click configuration for a LAN. +// The node broadcasts ARP requests if it wants to find a destination +// address, and it responds to ARP requests made for it. + +elementclass LanSimHost { + $ipaddr, $hwaddr | + + cl::Classifier(12/0806 20/0001,12/0806 20/0002, -); + forhost::IPClassifier(dst host $ipaddr,-); + arpquerier::ARPQuerier(eth0); + arpresponder::ARPResponder(eth0); + + ethout::Queue + -> ToDump(out_eth0.pcap,PER_NODE 1) + -> ToSimDevice(eth0); + + // All packets received on eth0 are silently + // dropped if they are destined for another location + FromSimDevice(eth0,4096) + -> ToDump(in_eth0.pcap,PER_NODE 1,ENCAP ETHER) + -> cl; + + // ARP queries from other nodes go to the ARP responder element + cl[0] -> arpresponder; + + // ARP responses go to our ARP query element + cl[1] -> [1]arpquerier; + + // All other packets get checked whether they are meant for us + cl[2] + -> Strip(14) + -> CheckIPHeader2 + -> MarkIPHeader + -> GetIPAddress(16) // Sets destination IP address annotation from packet data + -> forhost; + + // Packets for us are pushed outside + forhost[0] + ->[0]output; + + // Packets for other folks or broadcast packets get sent to output 1 + forhost[1] + -> ToDump(discard.pcap,2000,PER_NODE 1,ENCAP IP) + -> [1]output; + + // Incoming packets get pushed into the ARP query module + input[0] + -> arpquerier; + + // Both the ARP query and response modules send data out to + // the simulated network device, eth0. + arpquerier + -> ToDump(out_arpquery.pcap,PER_NODE 1) + -> ethout; + + arpresponder + -> ToDump(out_arprespond.pcap,PER_NODE 1) + -> ethout; + +} + +elementclass TapSimHost { + $dev | + + // It is mandatory to use an IPRouteTable element with ns-3-click + rt :: LinearIPLookup (172.16.1.0/24 0.0.0.0 1, 172.16.2.0/24 172.16.1.2 1); + + // Packets go to "tap0" which sends them to the kernel + input[0] + -> ToDump(tokernel.pcap,2000,IP,PER_NODE 1) + -> ToSimDevice($dev,IP); + + // Packets sent out by the "kernel" get pushed outside + FromSimDevice($dev,4096) + -> CheckIPHeader2 + -> ToDump(fromkernel.pcap,2000,IP,PER_NODE 1) + -> GetIPAddress(16) + -> rt + -> [0]output; + + rt[1] -> [0] output; +} + +// Instantiate elements +lan::LanSimHost(eth0:ip,eth0:eth); +kernel::TapSimHost(tap0); + +// Users can do some processing between the two elements +lan[0] -> kernel; +kernel -> lan; +// Packets for others or broadcasts are discarded +lan[1] -> Discard; + diff --git a/src/routing/click/examples/nsclick-routing-node2.click b/src/routing/click/examples/nsclick-routing-node2.click new file mode 100644 index 000000000..4fcfe0f6e --- /dev/null +++ b/src/routing/click/examples/nsclick-routing-node2.click @@ -0,0 +1,112 @@ +// nsclick-lan-single-interface.click +// +// Copyright (c) 2011, Deutsche Telekom Laboratories +// +// 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: Ruben Merz +// +// This is a single host Click configuration for a LAN. +// The node broadcasts ARP requests if it wants to find a destination +// address, and it responds to ARP requests made for it. + +elementclass LanSimHost { + $ipaddr, $hwaddr | + + cl::Classifier(12/0806 20/0001,12/0806 20/0002, -); + forhost::IPClassifier(dst host $ipaddr,-); + arpquerier::ARPQuerier(eth0); + arpresponder::ARPResponder(eth0); + + ethout::Queue + -> ToDump(out_eth0.pcap,PER_NODE 1) + -> ToSimDevice(eth0); + + // All packets received on eth0 are silently + // dropped if they are destined for another location + FromSimDevice(eth0,4096) + -> ToDump(in_eth0.pcap,PER_NODE 1,ENCAP ETHER) + -> cl; + + // ARP queries from other nodes go to the ARP responder element + cl[0] -> arpresponder; + + // ARP responses go to our ARP query element + cl[1] -> [1]arpquerier; + + // All other packets get checked whether they are meant for us + cl[2] + -> Strip(14) + -> CheckIPHeader2 + -> MarkIPHeader + -> GetIPAddress(16) // Sets destination IP address annotation from packet data + -> forhost; + + // Packets for us are pushed outside + forhost[0] + ->[0]output; + + // Packets for other folks or broadcast packets get sent to output 1 + forhost[1] + -> ToDump(discard.pcap,2000,PER_NODE 1,ENCAP IP) + -> [1]output; + + // Incoming packets get pushed into the ARP query module + input[0] + -> arpquerier; + + // Both the ARP query and response modules send data out to + // the simulated network device, eth0. + arpquerier + -> ToDump(out_arpquery.pcap,PER_NODE 1) + -> ethout; + + arpresponder + -> ToDump(out_arprespond.pcap,PER_NODE 1) + -> ethout; + +} + +elementclass TapSimHost { + $dev | + + // It is mandatory to use an IPRouteTable element with ns-3-click + rt :: LinearIPLookup (172.16.2.0/24 0.0.0.0 1,172.16.1.0/24 172.16.1.2 1); + + // Packets go to "tap0" which sends them to the kernel + input[0] + -> ToDump(tokernel.pcap,2000,IP,PER_NODE 1) + -> ToSimDevice($dev,IP); + + // Packets sent out by the "kernel" get pushed outside + FromSimDevice($dev,4096) + -> CheckIPHeader2 + -> ToDump(fromkernel.pcap,2000,IP,PER_NODE 1) + -> GetIPAddress(16) + -> rt + -> [0]output; + + rt[1] -> [0] output; +} + +// Instantiate elements +lan::LanSimHost(eth0:ip,eth0:eth); +kernel::TapSimHost(tap0); + +// Users can do some processing between the two elements +lan[0] -> kernel; +kernel -> lan; +// Packets for others or broadcasts are discarded +lan[1] -> Discard; + diff --git a/src/routing/click/examples/nsclick-routing.cc b/src/routing/click/examples/nsclick-routing.cc new file mode 100644 index 000000000..d0017f8a0 --- /dev/null +++ b/src/routing/click/examples/nsclick-routing.cc @@ -0,0 +1,134 @@ +/* -*- 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 + * + * Authors: Lalith Suresh + */ + +// Network topology +// +// +// 172.16.1.0/24 +// (1.1) (1.2) (1.3) (1.4) +// +// eth0 eth0 eth1 eth0 +// n0 ========= n1 ========= n2 +// LAN 1 LAN 2 +// +// - UDP flows from n0 to n2 via n1. +// - All nodes are Click based. +// + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/helper-module.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/ipv4-l3-click-protocol.h" +#include "ns3/click-internet-stack-helper.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("NsclickRouting"); + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_CLICK +// +// Enable logging for UdpClient and +// + LogComponentEnable ("NsclickRoutingClient", LOG_LEVEL_INFO); + LogComponentEnable ("NsclickRoutingServer", LOG_LEVEL_INFO); + +// +// Explicitly create the nodes required by the topology (shown above). +// + NS_LOG_INFO ("Create nodes."); + NodeContainer n; + n.Create (3); + +// +// Install Click on the nodes +// + ClickInternetStackHelper clickinternet; + clickinternet.SetClickFile (n.Get (0), "src/routing/click/examples/nsclick-routing-node0.click"); + clickinternet.SetClickFile (n.Get (1), "src/routing/click/examples/nsclick-ip-router.click"); + clickinternet.SetClickFile (n.Get (2), "src/routing/click/examples/nsclick-routing-node2.click"); + clickinternet.SetRoutingTableElement (n.Get (0), "kernel/rt"); + clickinternet.SetRoutingTableElement (n.Get (1), "u/rt"); + clickinternet.SetRoutingTableElement (n.Get (2), "kernel/rt"); + clickinternet.Install (n); + + NS_LOG_INFO ("Create channels."); +// +// Explicitly create the channels required by the topology (shown above). +// + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + csma.SetDeviceAttribute ("Mtu", UintegerValue (1400)); + NetDeviceContainer d01 = csma.Install (NodeContainer (n.Get (0), n.Get (1))); + NetDeviceContainer d12 = csma.Install (NodeContainer (n.Get (1), n.Get (2))); + + Ipv4AddressHelper ipv4; +// +// We've got the "hardware" in place. Now we need to add IP addresses. +// + NS_LOG_INFO ("Assign IP Addresses."); + ipv4.SetBase ("172.16.1.0", "255.255.255.0"); + Ipv4InterfaceContainer i01 = ipv4.Assign (d01); + + ipv4.SetBase ("172.16.2.0", "255.255.255.0"); + Ipv4InterfaceContainer i12 = ipv4.Assign (d12); + + NS_LOG_INFO ("Create Applications."); +// +// Create one udpServer applications on node one. +// + uint16_t port = 4000; + UdpServerHelper server (port); + ApplicationContainer apps = server.Install (n.Get(2)); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + +// +// Create one UdpClient application to send UDP datagrams from node zero to +// node one. +// + uint32_t MaxPacketSize = 1024; + Time interPacketInterval = Seconds (0.05); + uint32_t maxPacketCount = 320; + UdpClientHelper client (i12.GetAddress (1), port); + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (MaxPacketSize)); + apps = client.Install (NodeContainer (n.Get (0))); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + csma.EnablePcap ("nsclick-routing", d01, false); + csma.EnablePcap ("nsclick-routing", d12, false); + +// +// Now, do the actual simulation. +// + NS_LOG_INFO ("Run Simulation."); + Simulator::Stop (Seconds(20.0)); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +#else + NS_FATAL_ERROR ("Can't use ns-3-click without NSCLICK compiled in"); +#endif +} diff --git a/src/routing/click/examples/nsclick-simple-lan.cc b/src/routing/click/examples/nsclick-simple-lan.cc new file mode 100644 index 000000000..c3bb8ebfb --- /dev/null +++ b/src/routing/click/examples/nsclick-simple-lan.cc @@ -0,0 +1,97 @@ +/* -*- 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 + * + * Authors: Lalith Suresh + */ + +// Scenario: +// +// (Click) CSMA (non-Click) +// A ================ B +// (172.16.1.1) (172.16.1.2) +// (eth0) +// +// + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/helper-module.h" +#include "ns3/click-internet-stack-helper.h" +#include "ns3/log.h" + +using namespace ns3; + +void ReceivePacket (Ptr socket) +{ + NS_LOG_UNCOND ("Received one packet!"); +} + +int main (int argc, char *argv[]) +{ +#ifdef NS3_CLICK + NodeContainer csmaNodes; + csmaNodes.Create (2); + + // Setup CSMA channel between the nodes + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + NetDeviceContainer csmaDevices = csma.Install (csmaNodes); + + // Install normal internet stack on node B + InternetStackHelper internet; + internet.Install (csmaNodes.Get (1)); + + // Install Click on node A + ClickInternetStackHelper clickinternet; + clickinternet.SetClickFile (csmaNodes.Get (0), "src/routing/click/examples/nsclick-lan-single-interface.click"); + clickinternet.SetRoutingTableElement (csmaNodes.Get (0), "rt"); + clickinternet.Install (csmaNodes.Get (0)); + + // Configure IP addresses for the nodes + Ipv4AddressHelper ipv4; + ipv4.SetBase ("172.16.1.0", "255.255.255.0"); + ipv4.Assign (csmaDevices); + + // Configure traffic application and sockets + Address LocalAddress (InetSocketAddress (Ipv4Address::GetAny (), 50000)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", LocalAddress); + ApplicationContainer recvapp = packetSinkHelper.Install (csmaNodes.Get (1)); + recvapp.Start (Seconds (5.0)); + recvapp.Stop (Seconds (10.0)); + + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); + onOffHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onOffHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer appcont; + + AddressValue remoteAddress (InetSocketAddress (Ipv4Address ("172.16.1.2"), 50000)); + onOffHelper.SetAttribute ("Remote", remoteAddress); + appcont.Add (onOffHelper.Install (csmaNodes.Get (0))); + + appcont.Start (Seconds (5.0)); + appcont.Stop (Seconds (10.0)); + + // For tracing + csma.EnablePcap ("nsclick-simple-lan", csmaDevices, false); + + Simulator::Stop (Seconds(20.0)); + Simulator::Run(); + return 0; +#else + NS_FATAL_ERROR ("Can't use ns-3-click without NSCLICK compiled in"); +#endif +} diff --git a/src/routing/click/examples/nsclick-udp-client-server-csma.cc b/src/routing/click/examples/nsclick-udp-client-server-csma.cc new file mode 100644 index 000000000..c21ccc3ef --- /dev/null +++ b/src/routing/click/examples/nsclick-udp-client-server-csma.cc @@ -0,0 +1,126 @@ +/* -*- 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 + */ + +// Adaptation of examples/udp/udp-client-server.cc for +// Click based nodes. +// +// Network topology +// +// 172.16.1.0/24 +// (1.1) (1.2) (1.3) +// n0 n1 n2 +// | | | +// ============= +// LAN +// +// - UDP flows from n0 to n1 and n2 to n1 +// - All nodes are Click based. +// - The single ethernet interface that each node +// uses is named 'eth0' in the Click file. +// + +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/helper-module.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/click-internet-stack-helper.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("NsclickUdpClientServerCsma"); + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_CLICK +// +// Enable logging for UdpClient and +// + LogComponentEnable ("NsclickUdpClientServerCsma", LOG_LEVEL_INFO); + +// +// Explicitly create the nodes required by the topology (shown above). +// + NS_LOG_INFO ("Create nodes."); + NodeContainer n; + n.Create (3); + + NS_LOG_INFO ("Create channels."); +// +// Explicitly create the channels required by the topology (shown above). +// + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + csma.SetDeviceAttribute ("Mtu", UintegerValue (1400)); + NetDeviceContainer d = csma.Install (n); + +// +// Install Click on the nodes +// + ClickInternetStackHelper clickinternet; + clickinternet.SetClickFile (n, "src/routing/click/examples/nsclick-lan-single-interface.click"); + clickinternet.SetRoutingTableElement (n, "rt"); + clickinternet.Install (n); + + Ipv4AddressHelper ipv4; +// +// We've got the "hardware" in place. Now we need to add IP addresses. +// + NS_LOG_INFO ("Assign IP Addresses."); + ipv4.SetBase ("172.16.1.0", "255.255.255.0"); + Ipv4InterfaceContainer i = ipv4.Assign (d); + + NS_LOG_INFO ("Create Applications."); +// +// Create one udpServer applications on node one. +// + uint16_t port = 4000; + UdpServerHelper server (port); + ApplicationContainer apps = server.Install (n.Get(1)); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + +// +// Create one UdpClient application to send UDP datagrams from node zero to +// node one. +// + uint32_t MaxPacketSize = 1024; + Time interPacketInterval = Seconds (0.05); + uint32_t maxPacketCount = 320; + UdpClientHelper client (i.GetAddress (1), port); + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (MaxPacketSize)); + apps = client.Install (NodeContainer (n.Get (0), n.Get (2))); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + csma.EnablePcap ("nsclick-udp-client-server-csma", d, false); + +// +// Now, do the actual simulation. +// + NS_LOG_INFO ("Run Simulation."); + Simulator::Stop (Seconds(20.0)); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +#else + NS_FATAL_ERROR ("Can't use ns-3-click without NSCLICK compiled in"); +#endif +} diff --git a/src/routing/click/examples/nsclick-udp-client-server-wifi.cc b/src/routing/click/examples/nsclick-udp-client-server-wifi.cc new file mode 100644 index 000000000..e68267fff --- /dev/null +++ b/src/routing/click/examples/nsclick-udp-client-server-wifi.cc @@ -0,0 +1,199 @@ +/* -*- 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 + */ + +// Adaptation of examples/udp/udp-client-server.cc for +// Click based nodes running wifi. +// +// Network topology +// +// 172.16.1.0/24 +// (1.1) (1.2) (1.3) +// n0 )) (( n1 )) (( n2 +// WLAN +// +// - UDP flows from n0 to n1 +// - All nodes are Click based. +// - The single ethernet interface that each node +// uses is named 'eth0' in the Click file. +// + +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/helper-module.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/click-internet-stack-helper.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("NsclickUdpClientServerWifi"); + +#ifdef NS3_CLICK +void +readArp(Ptr clickRouter) +{ + // Access the handlers + NS_LOG_INFO(clickRouter->ReadHandler ("wifi/arpquerier", "table")); + NS_LOG_INFO(clickRouter->ReadHandler ("wifi/arpquerier", "stats")); +} + +void +writeArp(Ptr clickRouter) +{ + // Access the handler + NS_LOG_INFO(clickRouter->WriteHandler ("wifi/arpquerier", "insert", "172.16.1.2 00:00:00:00:00:02")); +} +#endif + +int +main (int argc, char *argv[]) +{ +#ifdef NS3_CLICK + + // + // Enable logging + // + LogComponentEnable ("NsclickUdpClientServerWifi", LOG_LEVEL_INFO); + + // + // Explicitly create the nodes required by the topology (shown above). + // + NS_LOG_INFO ("Create nodes."); + NodeContainer n; + n.Create (4); + + NS_LOG_INFO ("Create channels."); + // + // Explicitly create the channels required by the topology (shown above). + // + std::string phyMode ("DsssRate1Mbps"); + + // disable fragmentation for frames below 2200 bytes + Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200")); + // turn off RTS/CTS for frames below 2200 bytes + Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200")); + // Fix non-unicast data rate to be the same as that of unicast + Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", + StringValue (phyMode)); + + WifiHelper wifi; + wifi.SetStandard (WIFI_PHY_STANDARD_80211b); + + YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default (); + // This is one parameter that matters when using FixedRssLossModel + // set it to zero; otherwise, gain will be added + wifiPhy.Set ("RxGain", DoubleValue (0) ); + // ns-3 supports RadioTap and Prism tracing extensions for 802.11b + wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO); + + YansWifiChannelHelper wifiChannel ; + wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel"); + // The below FixedRssLossModel will cause the rss to be fixed regardless + // of the distance between the two stations, and the transmit power + wifiChannel.AddPropagationLoss ("ns3::FixedRssLossModel","Rss",DoubleValue(-80)); + wifiPhy.SetChannel (wifiChannel.Create ()); + + // Add a non-QoS upper mac, and disable rate control + NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default (); + wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode",StringValue(phyMode), + "ControlMode",StringValue(phyMode)); + // Set it to adhoc mode + wifiMac.SetType ("ns3::AdhocWifiMac"); + NetDeviceContainer d = wifi.Install (wifiPhy, wifiMac, n); + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (10.0, 0.0, 0.0)); + positionAlloc->Add (Vector (20.0, 0.0, 0.0)); + positionAlloc->Add (Vector (0.0, 10.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (n); + + // + // Install Click on the nodes + // + ClickInternetStackHelper clickinternet; + clickinternet.SetClickFile (n, "src/routing/click/examples/nsclick-wifi-single-interface.click"); + clickinternet.SetRoutingTableElement (n, "rt"); + clickinternet.Install (n); + // 4th node can listen to traffic in promisc mode + // Note: Promiscuous mode support for Click has + // been added ahead of the official Wifi support + // for promiscuous mode. Thus, the below line will + // not work until then. + n.Get(3)->GetObject()->SetPromiscuous ("eth0"); + + Ipv4AddressHelper ipv4; + // + // We've got the "hardware" in place. Now we need to add IP addresses. + // + NS_LOG_INFO ("Assign IP Addresses."); + ipv4.SetBase ("172.16.1.0", "255.255.255.0"); + Ipv4InterfaceContainer i = ipv4.Assign (d); + + NS_LOG_INFO ("Create Applications."); + // + // Create one udpServer applications on node one. + // + uint16_t port = 4000; + UdpServerHelper server (port); + ApplicationContainer apps = server.Install (n.Get(1)); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + + // + // Create one UdpClient application to send UDP datagrams from node zero to + // node one. + // + uint32_t MaxPacketSize = 1024; + Time interPacketInterval = Seconds (0.5); + uint32_t maxPacketCount = 320; + UdpClientHelper client (i.GetAddress (1), port); + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (MaxPacketSize)); + apps = client.Install (NodeContainer (n.Get (0), n.Get (2))); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + wifiPhy.EnablePcap ("nsclick-udp-client-server-wifi", d); + + // Force the MAC address of the second node: The current ARP + // implementation of Click sends only one ARP request per incoming + // packet for an unknown destination and does not retransmit if no + // response is received. With the scenario of this example, all ARP + // requests of node 3 are lost due to interference from node + // 1. Hence, we fill in the ARP table of node 2 before at the + // beginning of the simulation + Simulator::Schedule (Seconds (0.5), &readArp,n.Get(2)->GetObject()); + Simulator::Schedule (Seconds (0.6), &writeArp,n.Get(2)->GetObject()); + Simulator::Schedule (Seconds (0.7), &readArp,n.Get(2)->GetObject()); + + // + // Now, do the actual simulation. + // + NS_LOG_INFO ("Run Simulation."); + Simulator::Stop (Seconds(20.0)); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +#else + NS_FATAL_ERROR ("Can't use ns-3-click without NSCLICK compiled in"); +#endif +} diff --git a/src/routing/click/examples/nsclick-wifi-single-interface.click b/src/routing/click/examples/nsclick-wifi-single-interface.click new file mode 100644 index 000000000..fd31d05af --- /dev/null +++ b/src/routing/click/examples/nsclick-wifi-single-interface.click @@ -0,0 +1,113 @@ +// nsclick-wifi-single-interface.click +// +// Copyright (c) 2011, Deutsche Telekom Laboratories +// +// 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: Ruben Merz +// +// This is a single host Click configuration for wifi. +// The node broadcasts ARP requests if it wants to find a destination +// address, and it responds to ARP requests made for it. + +elementclass WiFiSimHost { + $ipaddr, $hwaddr | + + cl::Classifier(12/0806 20/0001,12/0806 20/0002, -); + forhost::IPClassifier(dst host $ipaddr,-); + arpquerier::ARPQuerier(eth0); + arpresponder::ARPResponder(eth0); + + ethout::Queue + -> ToDump(out_eth0.pcap,PER_NODE 1) + -> ToSimDevice(eth0); + + // All packets received on eth0 are silently + // dropped if they are destined for another location + FromSimDevice(eth0,4096) + -> ToDump(in_eth0.pcap,PER_NODE 1,ENCAP ETHER) + -> cl; + + // ARP queries from other nodes go to the ARP responder element + cl[0] -> arpresponder; + + // ARP responses go to our ARP query element + cl[1] -> [1]arpquerier; + + // All other packets get checked whether they are meant for us + cl[2] + -> Strip (14) + -> CheckIPHeader2 + -> MarkIPHeader + -> GetIPAddress(16) // Sets destination IP address annotation from packet data + -> forhost; + + // Packets for us are pushed outside + forhost[0] + ->[0]output; + + // Packets for other folks or broadcast packets get sent to output 1 + forhost[1] + -> ToDump(discard.pcap,2000,PER_NODE 1,ENCAP IP) + -> [1]output; + + // Incoming packets get pushed into the ARP query module + input[0] + -> arpquerier; + + // Both the ARP query and response modules send data out to + // the simulated network device, eth0. + arpquerier + -> ToDump(out_arpquery.pcap,PER_NODE 1) + -> ethout; + + arpresponder + -> ToDump(out_arprespond.pcap,PER_NODE 1) + -> ethout; + +} + +elementclass TapSimHost { + $dev | + + // Packets go to "tap0" which sends them to the kernel + input[0] + -> ToDump(tokernel.pcap,2000,IP,PER_NODE 1) + -> ToSimDevice($dev,IP); + + // Packets sent out by the "kernel" get pushed outside + FromSimDevice($dev,4096) + -> CheckIPHeader2 + -> ToDump(fromkernel.pcap,2000,IP,PER_NODE 1) + -> GetIPAddress(16) + -> [0]output; +} + +// Instantiate elements +wifi::WiFiSimHost(eth0:ip,eth0:eth); +kernel::TapSimHost(tap0); + +// Users can do some processing between the two elements +wifi[0] -> kernel; +kernel -> wifi; +// Packets not for us are discarded +wifi[1] -> Discard; + +// It is mandatory to use an IPRouteTable element with ns-3-click +// (but we do not use it in this example) +rt :: LinearIPLookup (172.16.1.0/24 0.0.0.0 1); +// We are actually not using the routing table +Idle () -> rt; +rt[0] -> Discard; +rt[1] -> Discard; diff --git a/src/routing/click/examples/wscript b/src/routing/click/examples/wscript new file mode 100644 index 000000000..afc0ae36c --- /dev/null +++ b/src/routing/click/examples/wscript @@ -0,0 +1,22 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_program('nsclick-simple-lan', + ['click', 'csma', 'internet-stack']) + obj.source = 'nsclick-simple-lan.cc' + + obj = bld.create_ns3_program('nsclick-raw-wlan', + ['click', 'wifi', 'internet-stack']) + obj.source = 'nsclick-raw-wlan.cc' + + obj = bld.create_ns3_program('nsclick-udp-client-server-csma', + ['click', 'csma', 'internet-stack']) + obj.source = 'nsclick-udp-client-server-csma.cc' + + obj = bld.create_ns3_program('nsclick-udp-client-server-wifi', + ['click', 'wifi', 'internet-stack']) + obj.source = 'nsclick-udp-client-server-wifi.cc' + + obj = bld.create_ns3_program('nsclick-routing', + ['click', 'csma', 'internet-stack']) + obj.source = 'nsclick-routing.cc' diff --git a/src/routing/click/helper/click-internet-stack-helper.cc b/src/routing/click/helper/click-internet-stack-helper.cc new file mode 100644 index 000000000..b3d3f41d6 --- /dev/null +++ b/src/routing/click/helper/click-internet-stack-helper.cc @@ -0,0 +1,503 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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: Mathieu Lacage + * Author: Faker Moatamri + * Author: Lalith Suresh + */ + +#ifdef NS3_CLICK + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/object.h" +#include "ns3/names.h" +#include "ns3/ipv4.h" +#include "ns3/packet-socket-factory.h" +#include "ns3/config.h" +#include "ns3/simulator.h" +#include "ns3/string.h" +#include "ns3/net-device.h" +#include "ns3/callback.h" +#include "ns3/node.h" +#include "ns3/core-config.h" +#include "ns3/arp-l3-protocol.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/ipv4-l3-click-protocol.h" +#include "ns3/trace-helper.h" +#include "click-internet-stack-helper.h" +#include +#include + +NS_LOG_COMPONENT_DEFINE ("ClickInternetStackHelper"); + +namespace ns3 { + +#define INTERFACE_CONTEXT + +typedef std::pair, uint32_t> InterfacePairIpv4; +typedef std::map > InterfaceFileMapIpv4; +typedef std::map > InterfaceStreamMapIpv4; + +static InterfaceFileMapIpv4 g_interfaceFileMapIpv4; /**< A mapping of Ipv4/interface pairs to pcap files */ +static InterfaceStreamMapIpv4 g_interfaceStreamMapIpv4; /**< A mapping of Ipv4/interface pairs to ascii streams */ + +ClickInternetStackHelper::ClickInternetStackHelper () + : m_ipv4Enabled (true) +{ + Initialize (); +} + +// private method called by both constructor and Reset () +void +ClickInternetStackHelper::Initialize () +{ + SetTcp ("ns3::TcpL4Protocol"); +} + +ClickInternetStackHelper::~ClickInternetStackHelper () +{ +} + +ClickInternetStackHelper::ClickInternetStackHelper (const ClickInternetStackHelper &o) +{ + m_ipv4Enabled = o.m_ipv4Enabled; + m_tcpFactory = o.m_tcpFactory; +} + +ClickInternetStackHelper & +ClickInternetStackHelper::operator = (const ClickInternetStackHelper &o) +{ + if (this == &o) + { + return *this; + } + return *this; +} + +void +ClickInternetStackHelper::Reset (void) +{ + m_ipv4Enabled = true; + Initialize (); +} + +void +ClickInternetStackHelper::SetTcp (const std::string tid) +{ + m_tcpFactory.SetTypeId (tid); +} + +void +ClickInternetStackHelper::SetTcp (std::string tid, std::string n0, const AttributeValue &v0) +{ + m_tcpFactory.SetTypeId (tid); + m_tcpFactory.Set (n0,v0); +} + +void +ClickInternetStackHelper::SetClickFile (NodeContainer c, std::string clickfile) +{ + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + SetClickFile (*i, clickfile); + } +} + +void +ClickInternetStackHelper::SetClickFile (Ptr node, std::string clickfile) +{ + m_nodeToClickFileMap.insert (std::make_pair (node, clickfile)); +} + +void +ClickInternetStackHelper::SetRoutingTableElement (NodeContainer c, std::string rt) +{ + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + SetRoutingTableElement (*i, rt); + } +} + +void +ClickInternetStackHelper::SetRoutingTableElement (Ptr node, std::string rt) +{ + m_nodeToRoutingTableElementMap.insert (std::make_pair (node, rt)); +} + +void +ClickInternetStackHelper::Install (NodeContainer c) const +{ + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + Install (*i); + } +} + +void +ClickInternetStackHelper::InstallAll (void) const +{ + Install (NodeContainer::GetGlobal ()); +} + +void +ClickInternetStackHelper::CreateAndAggregateObjectFromTypeId (Ptr node, const std::string typeId) +{ + ObjectFactory factory; + factory.SetTypeId (typeId); + Ptr protocol = factory.Create (); + node->AggregateObject (protocol); +} + +void +ClickInternetStackHelper::Install (Ptr node) const +{ + if (m_ipv4Enabled) + { + if (node->GetObject () != 0) + { + NS_FATAL_ERROR ("ClickInternetStackHelper::Install (): Aggregating " + "an InternetStack to a node with an existing Ipv4 object"); + return; + } + + CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol"); + CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3ClickProtocol"); + CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol"); + CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol"); + node->AggregateObject (m_tcpFactory.Create ()); + Ptr factory = CreateObject (); + node->AggregateObject (factory); + // Set routing + Ptr ipv4 = node->GetObject (); + Ptr ipv4Routing = CreateObject (); + std::map< Ptr, std::string >::const_iterator it; + it = m_nodeToClickFileMap.find (node); + + if (it != m_nodeToClickFileMap.end ()) + { + ipv4Routing->SetClickFile (it->second); + } + + it = m_nodeToRoutingTableElementMap.find (node); + if (it != m_nodeToRoutingTableElementMap.end ()) + { + ipv4Routing->SetClickRoutingTableElement (it->second); + } + ipv4->SetRoutingProtocol (ipv4Routing); + node->AggregateObject (ipv4Routing); + } +} + +void +ClickInternetStackHelper::Install (std::string nodeName) const +{ + Ptr node = Names::Find (nodeName); + Install (node); +} + +static void +Ipv4L3ProtocolRxTxSink (Ptr p, Ptr ipv4, uint32_t interface) +{ + NS_LOG_FUNCTION (p << ipv4 << interface); + + // + // Since trace sources are independent of interface, if we hook a source + // on a particular protocol we will get traces for all of its interfaces. + // We need to filter this to only report interfaces for which the user + // has expressed interest. + // + InterfacePairIpv4 pair = std::make_pair (ipv4, interface); + if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ()) + { + NS_LOG_INFO ("Ignoring packet to/from interface " << interface); + return; + } + + Ptr file = g_interfaceFileMapIpv4[pair]; + file->Write(Simulator::Now(), p); +} + +bool +ClickInternetStackHelper::PcapHooked (Ptr ipv4) +{ + for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin (); + i != g_interfaceFileMapIpv4.end (); + ++i) + { + if ((*i).first.first == ipv4) + { + return true; + } + } + return false; +} + +void +ClickInternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr ipv4, uint32_t interface, bool explicitFilename) +{ + NS_LOG_FUNCTION (prefix << ipv4 << interface); + + if (!m_ipv4Enabled) + { + NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled"); + return; + } + + // + // We have to create a file and a mapping from protocol/interface to file + // irrespective of how many times we want to trace a particular protocol. + // + PcapHelper pcapHelper; + + std::string filename; + if (explicitFilename) + { + filename = prefix; + } + else + { + filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface); + } + + Ptr file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW); + + // + // However, we only hook the trace source once to avoid multiple trace sink + // calls per event (connect is independent of interface). + // + if (!PcapHooked (ipv4)) + { + // + // Ptr is aggregated to node and Ipv4L3Protocol is aggregated to + // node so we can get to Ipv4L3Protocol through Ipv4. + // + Ptr ipv4L3Protocol = ipv4->GetObject (); + NS_ASSERT_MSG (ipv4L3Protocol, "ClickInternetStackHelper::EnablePcapIpv4Internal(): " + "m_ipv4Enabled and ipv4L3Protocol inconsistent"); + + bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv4L3ProtocolRxTxSink)); + NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): " + "Unable to connect ipv4L3Protocol \"Tx\""); + + result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv4L3ProtocolRxTxSink)); + NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): " + "Unable to connect ipv4L3Protocol \"Rx\""); + } + + g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file; +} + +static void +Ipv4L3ProtocolDropSinkWithoutContext ( + Ptr stream, + Ipv4Header const &header, + Ptr packet, + Ipv4L3Protocol::DropReason reason, + Ptr ipv4, + uint32_t interface) +{ + // + // Since trace sources are independent of interface, if we hook a source + // on a particular protocol we will get traces for all of its interfaces. + // We need to filter this to only report interfaces for which the user + // has expressed interest. + // + InterfacePairIpv4 pair = std::make_pair (ipv4, interface); + if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ()) + { + NS_LOG_INFO ("Ignoring packet to/from interface " << interface); + return; + } + + Ptr p = packet->Copy (); + p->AddHeader (header); + *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl; +} + +static void +Ipv4L3ProtocolDropSinkWithContext ( + Ptr stream, + std::string context, + Ipv4Header const &header, + Ptr packet, + Ipv4L3Protocol::DropReason reason, + Ptr ipv4, + uint32_t interface) +{ + // + // Since trace sources are independent of interface, if we hook a source + // on a particular protocol we will get traces for all of its interfaces. + // We need to filter this to only report interfaces for which the user + // has expressed interest. + // + InterfacePairIpv4 pair = std::make_pair (ipv4, interface); + if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ()) + { + NS_LOG_INFO ("Ignoring packet to/from interface " << interface); + return; + } + + Ptr p = packet->Copy (); + p->AddHeader (header); +#ifdef INTERFACE_CONTEXT + *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") " + << *p << std::endl; +#else + *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl; +#endif +} + +bool +ClickInternetStackHelper::AsciiHooked (Ptr ipv4) +{ + for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin (); + i != g_interfaceStreamMapIpv4.end (); + ++i) + { + if ((*i).first.first == ipv4) + { + return true; + } + } + return false; +} + +void +ClickInternetStackHelper::EnableAsciiIpv4Internal ( + Ptr stream, + std::string prefix, + Ptr ipv4, + uint32_t interface, + bool explicitFilename) +{ + if (!m_ipv4Enabled) + { + NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled"); + return; + } + + // + // Our trace sinks are going to use packet printing, so we have to + // make sure that is turned on. + // + Packet::EnablePrinting (); + + // + // If we are not provided an OutputStreamWrapper, we are expected to create + // one using the usual trace filename conventions and hook WithoutContext + // since there will be one file per context and therefore the context would + // be redundant. + // + if (stream == 0) + { + // + // Set up an output stream object to deal with private ofstream copy + // constructor and lifetime issues. Let the helper decide the actual + // name of the file given the prefix. + // + // We have to create a stream and a mapping from protocol/interface to + // stream irrespective of how many times we want to trace a particular + // protocol. + // + AsciiTraceHelper asciiTraceHelper; + + std::string filename; + if (explicitFilename) + { + filename = prefix; + } + else + { + filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface); + } + + Ptr theStream = asciiTraceHelper.CreateFileStream (filename); + + // + // However, we only hook the trace sources once to avoid multiple trace sink + // calls per event (connect is independent of interface). + // + if (!AsciiHooked (ipv4)) + { + // + // We can use the default drop sink for the ArpL3Protocol since it has + // the usual signature. We can get to the Ptr through + // our Ptr since they must both be aggregated to the same node. + // + Ptr arpL3Protocol = ipv4->GetObject (); + asciiTraceHelper.HookDefaultDropSinkWithoutContext (arpL3Protocol, "Drop", theStream); + + // + // The drop sink for the Ipv4L3Protocol uses a different signature than + // the default sink, so we have to cook one up for ourselves. We can get + // to the Ptr through our Ptr since they must both + // be aggregated to the same node. + // + Ptr ipv4L3Protocol = ipv4->GetObject (); + bool __attribute__ ((unused)) result = ipv4L3Protocol->TraceConnectWithoutContext ("Drop", + MakeBoundCallback (&Ipv4L3ProtocolDropSinkWithoutContext, + theStream)); + NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EanableAsciiIpv4Internal(): " + "Unable to connect ipv4L3Protocol \"Drop\""); + } + + g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = theStream; + return; + } + + // + // If we are provided an OutputStreamWrapper, we are expected to use it, and + // to provide a context. We are free to come up with our own context if we + // want, and use the AsciiTraceHelper Hook*WithContext functions, but for + // compatibility and simplicity, we just use Config::Connect and let it deal + // with the context. + // + // We need to associate the ipv4/interface with a stream to express interest + // in tracing events on that pair, however, we only hook the trace sources + // once to avoid multiple trace sink calls per event (connect is independent + // of interface). + // + if (!AsciiHooked (ipv4)) + { + Ptr node = ipv4->GetObject (); + std::ostringstream oss; + + // + // For the ARP Drop, we are going to use the default trace sink provided by + // the ascii trace helper. There is actually no AsciiTraceHelper in sight + // here, but the default trace sinks are actually publicly available static + // functions that are always there waiting for just such a case. + // + oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop"; + Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream)); + + // + // This has all kinds of parameters coming with, so we have to cook up our + // own sink. + // + oss.str (""); + oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop"; + Config::Connect (oss.str (), MakeBoundCallback (&Ipv4L3ProtocolDropSinkWithContext, stream)); + } + + g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream; +} + +} // namespace ns3 + +#endif // NS3_CLICK diff --git a/src/routing/click/helper/click-internet-stack-helper.h b/src/routing/click/helper/click-internet-stack-helper.h new file mode 100644 index 000000000..2f92db156 --- /dev/null +++ b/src/routing/click/helper/click-internet-stack-helper.h @@ -0,0 +1,230 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * 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: Mathieu Lacage + * Author: Lalith Suresh + */ + +#ifdef NS3_CLICK + +#ifndef CLICK_INTERNET_STACK_HELPER_H +#define CLICK_INTERNET_STACK_HELPER_H + +#include "ns3/node-container.h" +#include "ns3/net-device-container.h" +#include "ns3/packet.h" +#include "ns3/ptr.h" +#include "ns3/object-factory.h" +#include "ns3/ipv4-l3-protocol.h" +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/trace-helper.h" +#include + +namespace ns3 { + +class Node; +class Ipv4RoutingHelper; + +/** + * \brief aggregate Click/IP/TCP/UDP functionality to existing Nodes. + * + * This helper has been adapted from the InternetStackHelper class and + * nodes will not be able to use Ipv6 functionalities. + * + */ +class ClickInternetStackHelper : public PcapHelperForIpv4, public AsciiTraceHelperForIpv4 +{ +public: + /** + * Create a new ClickInternetStackHelper which uses Ipv4ClickRouting for routing + */ + ClickInternetStackHelper(void); + + /** + * Destroy the ClickInternetStackHelper + */ + virtual ~ClickInternetStackHelper(void); + ClickInternetStackHelper (const ClickInternetStackHelper &); + ClickInternetStackHelper &operator = (const ClickInternetStackHelper &o); + + /** + * Return helper internal state to that of a newly constructed one + */ + void Reset (void); + + /** + * Aggregate implementations of the ns3::Ipv4L3ClickProtocol, ns3::ArpL3Protocol, + * ns3::Udp, and ns3::Tcp classes onto the provided node. This method will + * assert if called on a node that already has an Ipv4 object aggregated to it. + * + * \param nodeName The name of the node on which to install the stack. + */ + void Install (std::string nodeName) const; + + /** + * Aggregate implementations of the ns3::Ipv4L3ClickProtocol, ns3::ArpL3Protocol, + * ns3::Udp, and ns3::Tcp classes onto the provided node. This method will + * assert if called on a node that already has an Ipv4 object aggregated to it. + * + * \param node The node on which to install the stack. + */ + void Install (Ptr node) const; + + /** + * For each node in the input container, aggregate implementations of the + * ns3::Ipv4L3ClickProtocol, ns3::ArpL3Protocol, ns3::Udp, and, ns3::Tcp classes. + * The program will assert if this method is called on a container with a + * node that already has an Ipv4 object aggregated to it. + * + * \param c NodeContainer that holds the set of nodes on which to install the + * new stacks. + */ + void Install (NodeContainer c) const; + + /** + * Aggregate IPv4, UDP, and TCP stacks to all nodes in the simulation + */ + void InstallAll (void) const; + + /** + * \brief set the Tcp stack which will not need any other parameter. + * + * This function sets up the tcp stack to the given TypeId. It should not be + * used for NSC stack setup because the nsc stack needs the Library attribute + * to be setup, please use instead the version that requires an attribute + * and a value. If you choose to use this function anyways to set nsc stack + * the default value for the linux library will be used: "liblinux2.6.26.so". + * + * \param tid the type id, typically it is set to "ns3::TcpL4Protocol" + */ + void SetTcp(std::string tid); + + /** + * \brief This function is used to setup the Network Simulation Cradle stack with library value. + * + * Give the NSC stack a shared library file name to use when creating the + * stack implementation. The attr string is actually the attribute name to + * be setup and val is its value. The attribute is the stack implementation + * to be used and the value is the shared library name. + * + * \param tid The type id, for the case of nsc it would be "ns3::NscTcpL4Protocol" + * \param attr The attribute name that must be setup, for example "Library" + * \param val The attribute value, which will be in fact the shared library name (example:"liblinux2.6.26.so") + */ + void SetTcp (std::string tid, std::string attr, const AttributeValue &val); + + /** + * \brief Set a Click file to be used for a group of nodes. + * \param c NodeContainer of nodes + * \param clickfile Click file to be used + */ + void SetClickFile (NodeContainer c, std::string clickfile); + + /** + * \brief Set a Click file to be used for a node. + * \param node Node for which Click file is to be set + * \param clickfile Click file to be used + */ + void SetClickFile (Ptr node, std::string clickfile); + + /** + * \brief Set a Click routing table element for a group of nodes. + * \param c NodeContainer of nodes + * \param rt Click Routing Table element name + */ + void SetRoutingTableElement (NodeContainer c, std::string rt); + + /** + * \brief Set a Click routing table element for a node. + * \param node Node for which Click file is to be set + * \param rt Click Routing Table element name + */ + void SetRoutingTableElement (Ptr node, std::string rt); +private: + /** + * @brief Enable pcap output the indicated Ipv4 and interface pair. + * @internal + * + * @param prefix Filename prefix to use for pcap files. + * @param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing. + * @param interface Interface ID on the Ipv4 on which you want to enable tracing. + */ + virtual void EnablePcapIpv4Internal (std::string prefix, + Ptr ipv4, + uint32_t interface, + bool explicitFilename); + + /** + * @brief Enable ascii trace output on the indicated Ipv4 and interface pair. + * @internal + * + * @param stream An OutputStreamWrapper representing an existing file to use + * when writing trace data. + * @param prefix Filename prefix to use for ascii trace files. + * @param ipv4 Ptr to the Ipv4 interface on which you want to enable tracing. + * @param interface Interface ID on the Ipv4 on which you want to enable tracing. + */ + virtual void EnableAsciiIpv4Internal (Ptr stream, + std::string prefix, + Ptr ipv4, + uint32_t interface, + bool explicitFilename); + + void Initialize (void); + ObjectFactory m_tcpFactory; + + /** + * \internal + */ + static void CreateAndAggregateObjectFromTypeId (Ptr node, const std::string typeId); + + /** + * \internal + */ + static void Cleanup (void); + + /** + * \internal + */ + bool PcapHooked (Ptr ipv4); + + /** + * \internal + */ + bool AsciiHooked (Ptr ipv4); + + /** + * \brief IPv4 install state (enabled/disabled) ? + */ + bool m_ipv4Enabled; + + /** + * \brief Node to Click file mapping + */ + std::map < Ptr, std::string > m_nodeToClickFileMap; + + /** + * \brief Node to Routing Table Element mapping + */ + std::map < Ptr, std::string > m_nodeToRoutingTableElementMap; +}; + +} // namespace ns3 + +#endif /* CLICK_INTERNET_STACK_HELPER_H */ + +#endif // NS3_CLICK diff --git a/src/routing/click/model/ipv4-click-routing.cc b/src/routing/click/model/ipv4-click-routing.cc new file mode 100644 index 000000000..37c0e532a --- /dev/null +++ b/src/routing/click/model/ipv4-click-routing.cc @@ -0,0 +1,646 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2010 Lalith Suresh + * + * 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 + * + * Authors: Lalith Suresh + */ + + +#ifdef NS3_CLICK + +#include "ns3/node.h" +#include "ns3/simulator.h" +#include "ns3/log.h" +#include "ns3/mac48-address.h" +#include "ns3/ipv4-interface.h" +#include "ns3/ipv4-l3-click-protocol.h" + +#include "ipv4-click-routing.h" +#include +#include + +#include +#include + +NS_LOG_COMPONENT_DEFINE ("Ipv4ClickRouting"); + +namespace ns3 { + +// Values from nsclick ExtRouter implementation +#define INTERFACE_ID_KERNELTAP 0 +#define INTERFACE_ID_FIRST 1 +#define INTERFACE_ID_FIRST_DROP 33 + +NS_OBJECT_ENSURE_REGISTERED (Ipv4ClickRouting); + +std::map < simclick_node_t *, Ptr > Ipv4ClickRouting::m_clickInstanceFromSimNode; + +TypeId +Ipv4ClickRouting::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ipv4ClickRouting") + .SetParent () + .AddConstructor () + ; + + return tid; +} + +Ipv4ClickRouting::Ipv4ClickRouting () + : m_nonDefaultName (false), + m_ipv4 (0) +{ +} + +Ipv4ClickRouting::~Ipv4ClickRouting () +{ +} + +void +Ipv4ClickRouting::DoStart () +{ + uint32_t id = m_ipv4->GetObject ()->GetId (); + + if (!m_nonDefaultName) + { + std::stringstream name; + name << "Node" << id; + m_nodeName = name.str (); + } + + m_simNode = new simclick_node_t; + timerclear (&m_simNode->curtime); + + AddSimNodeToClickMapping (); + + NS_ASSERT (m_clickFile.length () > 0); + + // Even though simclick_click_create() will halt programme execution + // if it is unable to initialise a Click router, we play safe + if (simclick_click_create (m_simNode, m_clickFile.c_str ()) >= 0) + { + NS_LOG_DEBUG (m_nodeName << " has initialised a Click Router"); + m_clickInitialised = true; + } + else + { + NS_LOG_DEBUG ("Click Router Initialisation failed for " << m_nodeName); + m_clickInitialised = false; + } + + NS_ASSERT (m_clickInitialised == true); + simclick_click_run (m_simNode); +} + +void +Ipv4ClickRouting::SetIpv4 (Ptr ipv4) +{ + m_ipv4 = ipv4; +} + +void +Ipv4ClickRouting::DoDispose () +{ + m_ipv4 = 0; + delete m_simNode; + Ipv4RoutingProtocol::DoDispose (); +} + +void +Ipv4ClickRouting::SetClickFile (std::string clickfile) +{ + m_clickFile = clickfile; +} + +void +Ipv4ClickRouting::SetClickRoutingTableElement (std::string name) +{ + m_clickRoutingTableElement = name; +} + +void +Ipv4ClickRouting::SetNodeName (std::string name) +{ + m_nodeName = name; + m_nonDefaultName = true; +} + +std::string +Ipv4ClickRouting::GetNodeName () +{ + return m_nodeName; +} + +int +Ipv4ClickRouting::GetInterfaceId (const char *ifname) +{ + int retval = -1; + + // The below hard coding of interface names follows the + // same approach as used in the original nsclick code for + // ns-2. The interface names map directly to what is to + // be used in the Click configuration files. + // Thus eth0 will refer to the first network device of + // the node, and is to be named so in the Click graph. + // This function is called by Click during the intialisation + // phase of the Click graph, during which it tries to map + // interface IDs to interface names. The return value + // corresponds to the interface ID that Click will use. + + // Tap/tun devices refer to the kernel devices + if (strstr(ifname, "tap") || strstr(ifname, "tun")) + { + retval = 0; + } + else if (const char *devname = strstr(ifname, "eth")) + { + while (*devname && !isdigit((unsigned char) *devname)) + { + devname++; + } + + if (*devname) + { + retval = atoi(devname) + INTERFACE_ID_FIRST; + } + } + else if (const char *devname = strstr(ifname, "drop")) + { + while (*devname && !isdigit((unsigned char) *devname)) + { + devname++; + } + if (*devname) + { + retval = atoi(devname) + INTERFACE_ID_FIRST_DROP; + } + } + + return retval; +} + +bool +Ipv4ClickRouting::IsInterfaceReady (int ifid) +{ + if (ifid >= 0 && ifid < (int) m_ipv4->GetNInterfaces ()) + { + return true; + } + else + { + return false; + } +} + +std::string +Ipv4ClickRouting::GetIpAddressFromInterfaceId (int ifid) +{ + std::stringstream addr; + m_ipv4->GetAddress (ifid, 0).GetLocal ().Print (addr); + + return addr.str (); +} + +std::string +Ipv4ClickRouting::GetMacAddressFromInterfaceId (int ifid) +{ + std::stringstream addr; + + Ptr device = m_ipv4->GetNetDevice (ifid); + Address devAddr = device->GetAddress (); + addr << Mac48Address::ConvertFrom(devAddr); + + return addr.str (); +} + +void +Ipv4ClickRouting::AddSimNodeToClickMapping () +{ + m_clickInstanceFromSimNode.insert (std::make_pair (m_simNode, this)); +} + +Ptr +Ipv4ClickRouting::GetClickInstanceFromSimNode (simclick_node_t *simnode) +{ + return m_clickInstanceFromSimNode[simnode]; +} + +void +Ipv4ClickRouting::RunClickEvent () +{ + m_simNode->curtime.tv_sec = Simulator::Now ().GetSeconds (); + m_simNode->curtime.tv_usec = Simulator::Now ().GetMicroSeconds () % 1000000; + simclick_click_run (m_simNode); +} + +void +Ipv4ClickRouting::HandleScheduleFromClick (const struct timeval *when) +{ + NS_LOG_DEBUG ("HandleScheduleFromClick at " << when->tv_sec << " " << when->tv_usec << " " << Simulator::Now ()); + + double simtime = when->tv_sec + (when->tv_usec / 1.0e6); + double simdelay = simtime - Simulator::Now ().GetMicroSeconds () / 1.0e6; + + Simulator::Schedule (Seconds (simdelay), &Ipv4ClickRouting::RunClickEvent, this); +} + +void +Ipv4ClickRouting::HandlePacketFromClick (int ifid, int ptype, const unsigned char* data, int len) +{ + NS_LOG_DEBUG ("HandlePacketFromClick"); + + // Figure out packet's destination here: + // If ifid == 0, then the packet's going up + // else, the packet's going down + if (ifid == 0) + { + NS_LOG_DEBUG ("Incoming packet from tap0. Sending Packet up the stack."); + Ptr ipv4l3 = DynamicCast (m_ipv4); + + Ptr p = Create (data, len); + + Ipv4Header ipHeader; + p->RemoveHeader (ipHeader); + + ipv4l3->LocalDeliver (p, ipHeader, (uint32_t) ifid); + } + else if (ifid) + { + NS_LOG_DEBUG ("Incoming packet from eth" << ifid - 1 << " of type " << ptype <<". Sending packet down the stack."); + + Ptr p = Create (data, len); + + DynamicCast (m_ipv4)->SendDown (p, ifid); + } +} + +void +Ipv4ClickRouting::SendPacketToClick (int ifid, int ptype, const unsigned char* data, int len) +{ + NS_LOG_FUNCTION (this << ifid); + m_simNode->curtime.tv_sec = Simulator::Now ().GetSeconds (); + m_simNode->curtime.tv_usec = Simulator::Now ().GetMicroSeconds () % 1000000; + + // Since packets in ns-3 don't have global Packet ID's and Flow ID's, we + // feed dummy values into pinfo. This avoids the need to make changes in the Click code + simclick_simpacketinfo pinfo; + pinfo.id = 0; + pinfo.fid = 0; + + simclick_click_send(m_simNode,ifid,ptype,data,len,&pinfo); +} + +void +Ipv4ClickRouting::Send (Ptr p, Ipv4Address src, Ipv4Address dst) +{ + uint32_t ifid; + + // Find out which interface holds the src address of the packet... + for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++) + { + Ipv4Address addr = m_ipv4->GetAddress (ifid, 0).GetLocal (); + + if (addr == src) + { + break; + } + } + + int len = p->GetSize (); + uint8_t *buf = new uint8_t [len]; + p->CopyData (buf, len); + + // ... and send the packet on the corresponding Click interface. + SendPacketToClick (0, SIMCLICK_PTYPE_IP, buf, len); + + delete [] buf; +} + +void +Ipv4ClickRouting::Receive (Ptr p, Mac48Address receiverAddr, Mac48Address dest) +{ + NS_LOG_FUNCTION (this << p << receiverAddr << dest); + + uint32_t ifid; + + // Find out which device this packet was received from... + for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++) + { + Ptr device = m_ipv4->GetNetDevice (ifid); + + if (Mac48Address::ConvertFrom (device->GetAddress ()) == receiverAddr) + { + break; + } + } + + int len = p->GetSize (); + uint8_t *buf = new uint8_t [len]; + p->CopyData (buf, len); + + //... and send the packet to the corresponding Click interface + SendPacketToClick (ifid, SIMCLICK_PTYPE_ETHER, buf, len); + + delete [] buf; +} + +std::string +Ipv4ClickRouting::ReadHandler (std::string elementName, std::string handlerName) +{ + std::string s = simclick_click_read_handler (m_simNode, elementName.c_str (), handlerName.c_str (), 0, 0); + return s; +} + +int +Ipv4ClickRouting::WriteHandler (std::string elementName, std::string handlerName, std::string writeString) +{ + int r = simclick_click_write_handler (m_simNode, elementName.c_str (), handlerName.c_str (), writeString.c_str ()); + + // Note: There are probably use-cases for returning + // a write handler's error code, so don't assert. + // For example, the 'add' handler for IPRouteTable + // type elements fails if the route to be added + // already exists. + + return r; +} + +void +Ipv4ClickRouting::SetPromiscuous (std::string ifName) +{ + Ptr ipv4l3 = DynamicCast (m_ipv4); + NS_ASSERT(ipv4l3); + // Interface ethN gets index 1+N, but netdevice will start at 0 + // To ensure this, install a Click stack on a node only after + // all NetDevices have been installed. + ipv4l3->SetPromisc (GetInterfaceId (ifName.c_str ()) - 1); +} + +Ptr +Ipv4ClickRouting::RouteOutput (Ptr p, const Ipv4Header &header, Ptr oif, Socket::SocketErrno &sockerr) +{ + Ptr rtentry; + + std::stringstream addr; + addr << "lookup "; + header.GetDestination ().Print (addr); + // Probe the Click Routing Table for the required IP + // This returns a string of the form "InterfaceID GatewayAddr" + std::string s = ReadHandler (m_clickRoutingTableElement, addr.str ()); + + int pos = s.find (" "); + + int interfaceId = atoi (s.substr (0, pos).c_str ()); + Ipv4Address destination (s.substr (pos + 1).c_str ()); + + if (interfaceId != -1) + { + rtentry = Create (); + rtentry->SetDestination (header.GetDestination ()); + // the source address is the interface address that matches + // the destination address (when multiple are present on the + // outgoing interface, one is selected via scoping rules) + NS_ASSERT (m_ipv4); + uint32_t numOifAddresses = m_ipv4->GetNAddresses (interfaceId); + NS_ASSERT (numOifAddresses > 0); + Ipv4InterfaceAddress ifAddr; + if (numOifAddresses == 1) + { + ifAddr = m_ipv4->GetAddress (interfaceId, 0); + } + else + { + NS_FATAL_ERROR ("XXX Not implemented yet: IP aliasing and Click"); + } + rtentry->SetSource (ifAddr.GetLocal ()); + rtentry->SetGateway (destination); + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceId)); + sockerr = Socket::ERROR_NOTERROR; + NS_LOG_DEBUG ("Found route to " << rtentry->GetDestination () + << " via nh " << rtentry->GetGateway () + << " with source addr " << rtentry->GetSource () + << " and output dev " << rtentry->GetOutputDevice()); + } + else + { + NS_LOG_DEBUG ("Click node " << m_nodeName + << ": RouteOutput for dest=" << header.GetDestination () + << " No route to host"); + sockerr = Socket::ERROR_NOROUTETOHOST; + } + + return rtentry; +} + +// This method should never be called since Click handles +// forwarding directly +bool +Ipv4ClickRouting::RouteInput (Ptr p, const Ipv4Header &header, + Ptr idev, UnicastForwardCallback ucb, + MulticastForwardCallback mcb, LocalDeliverCallback lcb, + ErrorCallback ecb) +{ + NS_FATAL_ERROR ("Click router does not have a RouteInput() interface!"); + return false; +} + +void +Ipv4ClickRouting::PrintRoutingTable (Ptr stream) const +{ +} + +void +Ipv4ClickRouting::NotifyInterfaceUp (uint32_t i) +{} + +void +Ipv4ClickRouting::NotifyInterfaceDown (uint32_t i) +{} + +void +Ipv4ClickRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address) +{} + +void +Ipv4ClickRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address) +{} + + +} // namespace ns3 + +static int simstrlcpy(char *buf, int len, const std::string &s) +{ + if (len) + { + len--; + + if ((unsigned) len > s.length()) + { + len = s.length(); + } + + s.copy(buf, len); + buf[len] = '\0'; + } + return 0; +} + +// Sends a Packet from Click to the Simulator: Defined in simclick.h. Click +// calls these methods. +int simclick_sim_send(simclick_node_t *simnode, + int ifid, int type, const unsigned char* data, int len, + simclick_simpacketinfo *pinfo) +{ + NS_LOG_DEBUG ("simclick_sim_send called at " << ns3::Simulator::Now().GetSeconds()<<": " << ifid << " " << type << " " << data << " "<< len); + + if (simnode == NULL) + { + return -1; + } + + ns3::Ptr clickInstance = ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode (simnode); + + clickInstance->HandlePacketFromClick (ifid, type, data, len); + + return 0; +} + +// Click Service Methods: Defined in simclick.h +int simclick_sim_command(simclick_node_t *simnode, int cmd, ...) +{ + va_list val; + va_start (val, cmd); + + int retval = 0; + + ns3::Ptr clickInstance = ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode (simnode); + switch (cmd) + { + case SIMCLICK_VERSION: + { + retval = 0; + break; + } + + case SIMCLICK_SUPPORTS: + { + int othercmd = va_arg (val, int); + retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_NODE_ID); + break; + } + + case SIMCLICK_IFID_FROM_NAME: + { + const char *ifname = va_arg(val, const char *); + + retval = clickInstance->GetInterfaceId (ifname); + + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IFID_FROM_NAME: " << ifname << " " << retval); + break; + } + + case SIMCLICK_IPADDR_FROM_NAME: + { + const char *ifname = va_arg(val, const char *); + char *buf = va_arg(val, char *); + int len = va_arg(val, int); + + int ifid = clickInstance->GetInterfaceId (ifname); + + if (ifid >= 0) + { + retval = simstrlcpy(buf, len, clickInstance->GetIpAddressFromInterfaceId (ifid)); + } + else + { + retval = -1; + } + + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IPADDR_FROM_NAME: "<< ifname << " "<< buf << " " << len); + break; + } + + case SIMCLICK_MACADDR_FROM_NAME: + { + const char *ifname = va_arg(val, const char *); + char *buf = va_arg(val, char *); + int len = va_arg(val, int); + int ifid = clickInstance->GetInterfaceId (ifname); + + if (ifid >= 0) + { + retval = simstrlcpy(buf, len, clickInstance->GetMacAddressFromInterfaceId (ifid)); + } + else + { + retval = -1; + } + + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_MACADDR_FROM_NAME: "<< ifname << " "<< buf << " "<< len); + break; + } + + case SIMCLICK_SCHEDULE: + { + const struct timeval *when = va_arg(val, const struct timeval *); + + clickInstance->HandleScheduleFromClick (when); + + retval = 0; + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_SCHEDULE: "<< when->tv_sec << "s and " << when->tv_usec << "usecs later."); + + break; + } + + case SIMCLICK_GET_NODE_NAME: + { + char *buf = va_arg(val, char *); + int len = va_arg(val, int); + retval = simstrlcpy(buf, len, clickInstance->GetNodeName ()); + + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_GET_NODE_NAME: " << buf << " " << len); + break; + } + + case SIMCLICK_IF_READY: + { + int ifid = va_arg(val, int); // Commented out so that optimized build works + + // We're not using a ClickQueue, so we're always ready (for the timebeing) + retval = clickInstance->IsInterfaceReady (ifid); + + NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IF_READY: " << ifid << " " << ns3::Simulator::Now ()); + break; + } + + case SIMCLICK_TRACE: + { + // Used only for tracing + NS_LOG_DEBUG (clickInstance->GetNodeName () << " Received a call for SIMCLICK_TRACE"); + break; + } + + case SIMCLICK_GET_NODE_ID: + { + // Used only for tracing + NS_LOG_DEBUG (clickInstance->GetNodeName () << " Received a call for SIMCLICK_GET_NODE_ID"); + break; + } + } + return retval; +} + +#endif // NS3_CLICK diff --git a/src/routing/click/model/ipv4-click-routing.h b/src/routing/click/model/ipv4-click-routing.h new file mode 100644 index 000000000..865c9d3c7 --- /dev/null +++ b/src/routing/click/model/ipv4-click-routing.h @@ -0,0 +1,247 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2010 Lalith Suresh + * + * 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 + * + * Authors: Lalith Suresh + */ + +#ifndef __IPV4_CLICK_ROUTING_H__ +#define __IPV4_CLICK_ROUTING_H__ + +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/ipv4.h" +#include "ns3/ipv4-routing-protocol.h" +#include "ns3/test.h" + +#include +#include + +#ifdef NS3_CLICK +#include +#endif + +#include +#include + +namespace ns3 { + +/** +* \ingroup click +* \brief Class to allow a node to use Click for external routing +*/ + +class Ipv4ClickRouting : public Ipv4RoutingProtocol +{ +#ifdef NS3_CLICK +public: + // Allow test cases to access private members + friend class ClickTrivialTest; + friend class ClickIfidFromNameTest; + friend class ClickIpMacAddressFromNameTest; + + static TypeId GetTypeId (void); + + Ipv4ClickRouting (); + virtual ~Ipv4ClickRouting (); + +protected: + virtual void DoStart (void); + +public: + virtual void DoDispose (); + + /** + * \brief Click configuration file to be used by the node's Click Instance. + * \param clickfile name of .click configuration file + */ + void SetClickFile (std::string clickfile); + + /** + * \brief Name of the node as to be used by Click. Required for Click Dumps. + * \param name Name to be assigned to the node. + */ + void SetNodeName (std::string name); + + /** + * \brief Name of the routing table element being used by Click. Required for RouteOutput () + * \param name Name of the routing table element. + */ + void SetClickRoutingTableElement (std::string name); + + /** + * \brief Read Handler interface for a node's Click Elements. + * Allows a user to read state information of a Click element. + * \param elementName name of the Click element + * \param handlerName name of the handler to be read + */ + std::string ReadHandler (std::string elementName, std::string handlerName); + + /** + * \brief Write Handler interface for a node's Click Elements + * Allows a user to modify state information of a Click element. + * \param elementName name of the Click element + * \param handlerName name of the handler to be read + * \param writeString string to be written using the write handler + */ + int WriteHandler (std::string elementName, std::string handlerName, std::string writeString); + + /** + * + * \brief Sets an interface to run on promiscuous mode. + */ + void SetPromiscuous (std::string ifName); + +private: + simclick_node_t *m_simNode; + + /** + * \brief Provide a mapping between the node reference used by Click and the corresponding Ipv4ClickRouting instance. + */ + static std::map < simclick_node_t *, Ptr > m_clickInstanceFromSimNode; + +public: + /** + * \brief Allows the Click service methods, which reside outside Ipv4ClickRouting, to get the required Ipv4ClickRouting instances. + * \param simnode The Click simclick_node_t instance for which the Ipv4ClickRouting instance is required + * \return A Ptr to the required Ipv4ClickRouting instance + */ + static Ptr GetClickInstanceFromSimNode (simclick_node_t *simnode); + +public: + + /** + * \brief Provides for SIMCLICK_IFID_FROM_NAME + * \param ifname The name of the interface + * \return The interface ID which corresponds to ifname + */ + int GetInterfaceId (const char *ifname); + + /** + * \brief Provides for SIMCLICK_IPADDR_FROM_NAME + * \param ifid The interface ID for which the IP Address is required + * \return The IP Address of the interface in string format + */ + std::string GetIpAddressFromInterfaceId (int ifid); + + /** + * \brief Provides for SIMCLICK_MACADDR_FROM_NAME + * \param ifid The interface ID for which the MAC Address is required + * \return The MAC Address of the interface in string format + */ + std::string GetMacAddressFromInterfaceId (int ifid); + + /** + * \brief Provides for SIMCLICK_GET_NODE_NAME + * \return The Node name + */ + std::string GetNodeName (); + + /** + * \brief Provides for SIMCLICK_IF_READY + * \return Returns 1, if the interface is ready, -1 if ifid is invalid + */ + bool IsInterfaceReady (int ifid); + + /** + * \brief Set the Ipv4 instance to be used + * \param ipv4 The Ipv4 instance + */ + virtual void SetIpv4 (Ptr ipv4); + +private: + /** + * \brief Used internally in DoStart () to Add a mapping to m_clickInstanceFromSimNode mapping + */ + void AddSimNodeToClickMapping (); + + /** + * \brief This method has to be scheduled everytime Click calls SIMCLICK_SCHEDULE + */ + void RunClickEvent (); + +public: + + /** + * \brief Schedules simclick_click_run to run at the given time + * \param when Time at which the simclick_click_run instance should be run + */ + void HandleScheduleFromClick (const struct timeval *when); + + /** + * \brief Receives a packet from Click + * \param ifid The interface ID from which the packet is arriving + * \param type The type of packet as defined in click/simclick.h + * \param data The contents of the packet + * \param len The length of the packet + */ + void HandlePacketFromClick (int ifid, int type, const unsigned char *data, int len); + + /** + * \brief Sends a packet to Click + * \param ifid The interface ID from which the packet is arriving + * \param type The type of packet as defined in click/simclick.h + * \param data The contents of the packet + * \param len The length of the packet + */ + void SendPacketToClick (int ifid, int type, const unsigned char *data, int len); + + /** + * \brief Allow a higher layer to send data through Click. (From Ipv4ExtRouting) + * \param p The packet to be sent + * \param src The source IP Address + * \param dest The destination IP Address + */ + void Send (Ptr p, Ipv4Address src, Ipv4Address dest); + + /** + * \brief Allow a lower layer to send data to Click. (From Ipv4ExtRouting) + * \param p The packet to be sent + * \param receiverAddr Receiving interface's address + * \param dest The Destination MAC address + */ + void Receive (Ptr p, Mac48Address receiverAddr, Mac48Address dest); + + // From Ipv4RoutingProtocol + virtual Ptr RouteOutput (Ptr p, const Ipv4Header &header, Ptr oif, Socket::SocketErrno &sockerr); + virtual bool RouteInput (Ptr p, const Ipv4Header &header, Ptr idev, + UnicastForwardCallback ucb, MulticastForwardCallback mcb, + LocalDeliverCallback lcb, ErrorCallback ecb); + virtual void PrintRoutingTable (Ptr stream) const; + virtual void NotifyInterfaceUp (uint32_t interface); + virtual void NotifyInterfaceDown (uint32_t interface); + virtual void NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address); + virtual void NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address); + +private: + std::string m_clickFile; + std::string m_nodeName; + std::string m_clickRoutingTableElement; + + + std::map < std::string, uint32_t > m_ifaceIdFromName; + std::map < std::string, Address > m_ifaceMacFromName; + std::map < std::string, Ipv4Address > m_ifaceAddrFromName; + bool m_clickInitialised; + bool m_nonDefaultName; + + Ptr m_ipv4; +#endif //NS3_CLICK +}; + +} // namespace ns3 + +#endif // __IPV4_CLICK_ROUTING_H__ diff --git a/src/routing/click/model/ipv4-l3-click-protocol.cc b/src/routing/click/model/ipv4-l3-click-protocol.cc new file mode 100644 index 000000000..277803f67 --- /dev/null +++ b/src/routing/click/model/ipv4-l3-click-protocol.cc @@ -0,0 +1,818 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// +// 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: George F. Riley +// Author: Lalith Suresh +// + +#ifdef NS3_CLICK + +#include "ipv4-l3-click-protocol.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/node.h" +#include "ns3/socket.h" +#include "ns3/ethernet-header.h" +#include "ns3/llc-snap-header.h" +#include "ns3/net-device.h" +#include "ns3/uinteger.h" +#include "ns3/object-vector.h" + +#include "ns3/ipv4-raw-socket-impl.h" +#include "ns3/arp-l3-protocol.h" +#include "ns3/ipv4-l4-protocol.h" +#include "ns3/icmpv4-l4-protocol.h" +#include "ns3/loopback-net-device.h" + +NS_LOG_COMPONENT_DEFINE ("Ipv4L3ClickProtocol"); + +namespace ns3 { + +const uint16_t Ipv4L3ClickProtocol::PROT_NUMBER = 0x0800; + + +NS_OBJECT_ENSURE_REGISTERED (Ipv4L3ClickProtocol); + +TypeId +Ipv4L3ClickProtocol::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ipv4L3ClickProtocol") + .SetParent () + .AddConstructor () + .AddAttribute ("DefaultTtl", "The TTL value set by default on all outgoing packets generated on this node.", + UintegerValue (64), + MakeUintegerAccessor (&Ipv4L3ClickProtocol::m_defaultTtl), + MakeUintegerChecker ()) + .AddAttribute ("InterfaceList", "The set of Ipv4 interfaces associated to this Ipv4 stack.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&Ipv4L3ClickProtocol::m_interfaces), + MakeObjectVectorChecker ()) + ; + return tid; +} + +Ipv4L3ClickProtocol::Ipv4L3ClickProtocol () + : m_identification (0) +{ +} + +Ipv4L3ClickProtocol::~Ipv4L3ClickProtocol () +{ +} + +void +Ipv4L3ClickProtocol::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) + { + *i = 0; + } + m_protocols.clear (); + + for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i) + { + *i = 0; + } + m_interfaces.clear (); + m_sockets.clear (); + m_node = 0; + m_routingProtocol = 0; + Object::DoDispose (); +} + +void +Ipv4L3ClickProtocol::NotifyNewAggregate () +{ + if (m_node == 0) + { + Ptrnode = this->GetObject(); + // verify that it's a valid node and that + // the node has not been set before + if (node != 0) + { + this->SetNode (node); + } + } + Object::NotifyNewAggregate (); +} + +void +Ipv4L3ClickProtocol::SetRoutingProtocol (Ptr routingProtocol) +{ + NS_LOG_FUNCTION (this); + m_routingProtocol = routingProtocol; + m_routingProtocol->SetIpv4 (this); +} + + +Ptr +Ipv4L3ClickProtocol::GetRoutingProtocol (void) const +{ + return m_routingProtocol; +} + +Ptr +Ipv4L3ClickProtocol::GetInterface (uint32_t index) const +{ + NS_LOG_FUNCTION (this << index); + if (index < m_interfaces.size ()) + { + return m_interfaces[index]; + } + return 0; +} + +uint32_t +Ipv4L3ClickProtocol::GetNInterfaces (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_interfaces.size (); +} + +int32_t +Ipv4L3ClickProtocol::GetInterfaceForAddress ( + Ipv4Address address) const +{ + NS_LOG_FUNCTION (this << address); + + int32_t interface = 0; + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); + i != m_interfaces.end (); + i++, interface++) + { + for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++) + { + if ((*i)->GetAddress (j).GetLocal () == address) + { + return interface; + } + } + } + + return -1; +} + +int32_t +Ipv4L3ClickProtocol::GetInterfaceForPrefix ( + Ipv4Address address, + Ipv4Mask mask) const +{ + NS_LOG_FUNCTION (this << address << mask); + + int32_t interface = 0; + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); + i != m_interfaces.end (); + i++, interface++) + { + for (uint32_t j = 0; j < (*i)->GetNAddresses (); j++) + { + if ((*i)->GetAddress (j).GetLocal ().CombineMask (mask) == address.CombineMask (mask)) + { + return interface; + } + } + } + + return -1; +} + +int32_t +Ipv4L3ClickProtocol::GetInterfaceForDevice ( + Ptr device) const +{ + NS_LOG_FUNCTION (this << device->GetIfIndex()); + + int32_t interface = 0; + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); + i != m_interfaces.end (); + i++, interface++) + { + if ((*i)->GetDevice () == device) + { + return interface; + } + } + + return -1; +} + +bool +Ipv4L3ClickProtocol::IsDestinationAddress (Ipv4Address address, uint32_t iif) const +{ + NS_LOG_FUNCTION (this << address << " " << iif); + + // First check the incoming interface for a unicast address match + for (uint32_t i = 0; i < GetNAddresses (iif); i++) + { + Ipv4InterfaceAddress iaddr = GetAddress (iif, i); + if (address == iaddr.GetLocal ()) + { + NS_LOG_LOGIC ("For me (destination " << address << " match)"); + return true; + } + if (address == iaddr.GetBroadcast ()) + { + NS_LOG_LOGIC ("For me (interface broadcast address)"); + return true; + } + } + + if (address.IsMulticast ()) + { +#ifdef NOTYET + if (MulticastCheckGroup (iif, address )) +#endif + if (true) + { + NS_LOG_LOGIC ("For me (Ipv4Addr multicast address"); + return true; + } + } + + if (address.IsBroadcast ()) + { + NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)"); + return true; + } + + if (GetWeakEsModel ()) // Check other interfaces + { + for (uint32_t j = 0; j < GetNInterfaces (); j++) + { + if (j == uint32_t (iif)) continue; + for (uint32_t i = 0; i < GetNAddresses (j); i++) + { + Ipv4InterfaceAddress iaddr = GetAddress (j, i); + if (address == iaddr.GetLocal ()) + { + NS_LOG_LOGIC ("For me (destination " << address << " match) on another interface"); + return true; + } + // This is a small corner case: match another interface's broadcast address + if (address == iaddr.GetBroadcast ()) + { + NS_LOG_LOGIC ("For me (interface broadcast address on another interface)"); + return true; + } + } + } + } + return false; +} + +void +Ipv4L3ClickProtocol::SetIpForward (bool forward) +{ + NS_LOG_FUNCTION (this << forward); + m_ipForward = forward; + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) + { + (*i)->SetForwarding (forward); + } +} + +bool +Ipv4L3ClickProtocol::GetIpForward (void) const +{ + return m_ipForward; +} + +void +Ipv4L3ClickProtocol::SetWeakEsModel (bool model) +{ + m_weakEsModel = model; +} + +bool +Ipv4L3ClickProtocol::GetWeakEsModel (void) const +{ + return m_weakEsModel; +} + +Ptr +Ipv4L3ClickProtocol::GetNetDevice (uint32_t i) +{ + NS_LOG_FUNCTION (this << i); + return GetInterface (i)->GetDevice (); +} + +void +Ipv4L3ClickProtocol::SetDefaultTtl (uint8_t ttl) +{ + NS_LOG_FUNCTION_NOARGS (); + m_defaultTtl = ttl; +} + +void +Ipv4L3ClickProtocol::SetupLoopback (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + Ptr interface = CreateObject (); + Ptr device = 0; + // First check whether an existing LoopbackNetDevice exists on the node + for (uint32_t i = 0; i < m_node->GetNDevices (); i++) + { + if (device = DynamicCast (m_node->GetDevice (i))) + { + break; + } + } + if (device == 0) + { + device = CreateObject (); + m_node->AddDevice (device); + } + interface->SetDevice (device); + interface->SetNode (m_node); + Ipv4InterfaceAddress ifaceAddr = Ipv4InterfaceAddress (Ipv4Address::GetLoopback (), Ipv4Mask::GetLoopback ()); + interface->AddAddress (ifaceAddr); + uint32_t index = AddIpv4Interface (interface); + Ptr node = GetObject (); + node->RegisterProtocolHandler (MakeCallback (&Ipv4L3ClickProtocol::Receive, this), + Ipv4L3ClickProtocol::PROT_NUMBER, device); + interface->SetUp (); + if (m_routingProtocol != 0) + { + m_routingProtocol->NotifyInterfaceUp (index); + } +} + +Ptr +Ipv4L3ClickProtocol::CreateRawSocket (void) +{ + NS_LOG_FUNCTION (this); + Ptr socket = CreateObject (); + socket->SetNode (m_node); + m_sockets.push_back (socket); + return socket; +} +void +Ipv4L3ClickProtocol::DeleteRawSocket (Ptr socket) +{ + NS_LOG_FUNCTION (this << socket); + for (SocketList::iterator i = m_sockets.begin (); i != m_sockets.end (); ++i) + { + if ((*i) == socket) + { + m_sockets.erase (i); + return; + } + } + return; +} + + +void +Ipv4L3ClickProtocol::SetNode (Ptr node) +{ + m_node = node; + // Add a LoopbackNetDevice if needed, and an Ipv4Interface on top of it + SetupLoopback (); +} + +bool +Ipv4L3ClickProtocol::AddAddress (uint32_t i, Ipv4InterfaceAddress address) +{ + NS_LOG_FUNCTION (this << i << address); + Ptr interface = GetInterface (i); + bool retVal = interface->AddAddress (address); + if (m_routingProtocol != 0) + { + m_routingProtocol->NotifyAddAddress (i, address); + } + return retVal; +} + +Ipv4InterfaceAddress +Ipv4L3ClickProtocol::GetAddress (uint32_t interfaceIndex, uint32_t addressIndex) const +{ + NS_LOG_FUNCTION (this << interfaceIndex << addressIndex); + Ptr interface = GetInterface (interfaceIndex); + return interface->GetAddress (addressIndex); +} + +uint32_t +Ipv4L3ClickProtocol::GetNAddresses (uint32_t interface) const +{ + NS_LOG_FUNCTION (this << interface); + Ptr iface = GetInterface (interface); + return iface->GetNAddresses (); +} + +bool +Ipv4L3ClickProtocol::RemoveAddress (uint32_t i, uint32_t addressIndex) +{ + NS_LOG_FUNCTION (this << i << addressIndex); + Ptr interface = GetInterface (i); + Ipv4InterfaceAddress address = interface->RemoveAddress (addressIndex); + if (address != Ipv4InterfaceAddress ()) + { + if (m_routingProtocol != 0) + { + m_routingProtocol->NotifyRemoveAddress (i, address); + } + return true; + } + return false; +} + +Ipv4Address +Ipv4L3ClickProtocol::SelectSourceAddress (Ptr device, + Ipv4Address dst, Ipv4InterfaceAddress::InterfaceAddressScope_e scope) +{ + NS_LOG_FUNCTION (device << dst << scope); + Ipv4Address addr ("0.0.0.0"); + Ipv4InterfaceAddress iaddr; + bool found = false; + + if (device != 0) + { + int32_t i = GetInterfaceForDevice (device); + NS_ASSERT_MSG (i >= 0, "No device found on node"); + for (uint32_t j = 0; j < GetNAddresses (i); j++) + { + iaddr = GetAddress (i, j); + if (iaddr.IsSecondary ()) continue; + if (iaddr.GetScope () > scope) continue; + if (dst.CombineMask (iaddr.GetMask ()) == iaddr.GetLocal ().CombineMask (iaddr.GetMask ()) ) + { + return iaddr.GetLocal (); + } + if (!found) + { + addr = iaddr.GetLocal (); + found = true; + } + } + } + if (found) + { + return addr; + } + + // Iterate among all interfaces + for (uint32_t i = 0; i < GetNInterfaces (); i++) + { + for (uint32_t j = 0; j < GetNAddresses (i); j++) + { + iaddr = GetAddress (i, j); + if (iaddr.IsSecondary ()) continue; + if (iaddr.GetScope () != Ipv4InterfaceAddress::LINK + && iaddr.GetScope () <= scope) + { + return iaddr.GetLocal (); + } + } + } + NS_LOG_WARN ("Could not find source address for " << dst << " and scope " + << scope << ", returning 0"); + return addr; +} + +void +Ipv4L3ClickProtocol::SetMetric (uint32_t i, uint16_t metric) +{ + NS_LOG_FUNCTION (i << metric); + Ptr interface = GetInterface (i); + interface->SetMetric (metric); +} + +uint16_t +Ipv4L3ClickProtocol::GetMetric (uint32_t i) const +{ + NS_LOG_FUNCTION (i); + Ptr interface = GetInterface (i); + return interface->GetMetric (); +} + +uint16_t +Ipv4L3ClickProtocol::GetMtu (uint32_t i) const +{ + NS_LOG_FUNCTION (this << i); + Ptr interface = GetInterface (i); + return interface->GetDevice ()->GetMtu (); +} + +bool +Ipv4L3ClickProtocol::IsUp (uint32_t i) const +{ + NS_LOG_FUNCTION (this << i); + Ptr interface = GetInterface (i); + return interface->IsUp (); +} + +void +Ipv4L3ClickProtocol::SetUp (uint32_t i) +{ + NS_LOG_FUNCTION (this << i); + Ptr interface = GetInterface (i); + interface->SetUp (); + + if (m_routingProtocol != 0) + { + m_routingProtocol->NotifyInterfaceUp (i); + } +} + +void +Ipv4L3ClickProtocol::SetDown (uint32_t ifaceIndex) +{ + NS_LOG_FUNCTION (this << ifaceIndex); + Ptr interface = GetInterface (ifaceIndex); + interface->SetDown (); + + if (m_routingProtocol != 0) + { + m_routingProtocol->NotifyInterfaceDown (ifaceIndex); + } +} + +bool +Ipv4L3ClickProtocol::IsForwarding (uint32_t i) const +{ + NS_LOG_FUNCTION (this << i); + Ptr interface = GetInterface (i); + NS_LOG_LOGIC ("Forwarding state: " << interface->IsForwarding ()); + return interface->IsForwarding (); +} + +void +Ipv4L3ClickProtocol::SetForwarding (uint32_t i, bool val) +{ + NS_LOG_FUNCTION (this << i); + Ptr interface = GetInterface (i); + interface->SetForwarding (val); +} + +void +Ipv4L3ClickProtocol::SetPromisc (uint32_t i) +{ + NS_ASSERT(i <= m_node->GetNDevices ()); + if (i > m_promiscDeviceList.size ()) + { + m_promiscDeviceList.resize (i); + } + std::vector::iterator it = m_promiscDeviceList.begin(); + std::advance (it, i); + m_promiscDeviceList.insert (it, true); +} + +uint32_t +Ipv4L3ClickProtocol::AddInterface (Ptr device) +{ + NS_LOG_FUNCTION (this << &device); + + Ptr node = GetObject (); + NS_LOG_DEBUG("Size:" << m_promiscDeviceList.size () << " Interface index" << device->GetIfIndex ()); + if (m_promiscDeviceList.size () > 0 && + (m_promiscDeviceList.size () >= device->GetIfIndex ()) && + (m_promiscDeviceList[device->GetIfIndex ()])) + { + node->RegisterProtocolHandler (MakeCallback (&Ipv4L3ClickProtocol::Receive, this), + 0, device,true); + } + else + { + node->RegisterProtocolHandler (MakeCallback (&Ipv4L3ClickProtocol::Receive, this), + Ipv4L3ClickProtocol::PROT_NUMBER, device); + } + node->RegisterProtocolHandler (MakeCallback (&Ipv4L3ClickProtocol::Receive, this), + ArpL3Protocol::PROT_NUMBER, device); + + Ptr interface = CreateObject (); + interface->SetNode (m_node); + interface->SetDevice (device); + interface->SetForwarding (m_ipForward); + return AddIpv4Interface (interface); +} + +uint32_t +Ipv4L3ClickProtocol::AddIpv4Interface (Ptrinterface) +{ + NS_LOG_FUNCTION (this << interface); + uint32_t index = m_interfaces.size (); + m_interfaces.push_back (interface); + return index; +} + +// XXX when should we set ip_id? check whether we are incrementing +// m_identification on packets that may later be dropped in this stack +// and whether that deviates from Linux +Ipv4Header +Ipv4L3ClickProtocol::BuildHeader ( + Ipv4Address source, + Ipv4Address destination, + uint8_t protocol, + uint16_t payloadSize, + uint8_t ttl, + bool mayFragment) +{ + NS_LOG_FUNCTION_NOARGS (); + Ipv4Header ipHeader; + ipHeader.SetSource (source); + ipHeader.SetDestination (destination); + ipHeader.SetProtocol (protocol); + ipHeader.SetPayloadSize (payloadSize); + ipHeader.SetTtl (ttl); + if (mayFragment == true) + { + ipHeader.SetMayFragment (); + ipHeader.SetIdentification (m_identification); + m_identification++; + } + else + { + ipHeader.SetDontFragment (); + // TBD: set to zero here; will cause traces to change + ipHeader.SetIdentification (m_identification); + m_identification++; + } + if (Node::ChecksumEnabled ()) + { + ipHeader.EnableChecksum (); + } + return ipHeader; +} + +void +Ipv4L3ClickProtocol::Send (Ptr packet, + Ipv4Address source, + Ipv4Address destination, + uint8_t protocol, + Ptr route) +{ + NS_LOG_FUNCTION (this << packet << source << destination << uint32_t(protocol) << route); + + Ipv4Header ipHeader; + bool mayFragment = true; + uint8_t ttl = m_defaultTtl; + SocketIpTtlTag tag; + bool found = packet->RemovePacketTag (tag); + if (found) + { + ttl = tag.GetTtl (); + } + + ipHeader = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, mayFragment); + Ptr click = DynamicCast (m_routingProtocol); + if (Node::ChecksumEnabled ()) + { + ipHeader.EnableChecksum (); + } + packet->AddHeader (ipHeader); + click->Send (packet->Copy (), source, destination); + return; +} + +void +Ipv4L3ClickProtocol::SendDown (Ptr p, int ifid) +{ + // Called by Ipv4ClickRouting. + + // NetDevice::Send () attaches ethernet headers, + // so the one that Click attaches isn't required + // but we need the destination address and + // protocol values from the header. + + Ptr netdev = GetNetDevice (ifid); + + EthernetHeader header; + p->RemoveHeader (header); + + uint16_t protocol; + + if (header.GetLengthType () <= 1500) + { + LlcSnapHeader llc; + p->RemoveHeader (llc); + protocol = llc.GetType (); + } + else + { + protocol = header.GetLengthType (); + } + + // Use the destination address and protocol obtained + // from above to send the packet. + netdev->Send (p, header.GetDestination (), protocol); +} + +void +Ipv4L3ClickProtocol::Receive( Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType) +{ + NS_LOG_FUNCTION (this << device << p << from << to); + Ptr packet = p->Copy (); + + // Add an ethernet frame. This allows + // Click to work with csma and wifi + EthernetHeader hdr; + hdr.SetSource (Mac48Address::ConvertFrom (from)); + hdr.SetDestination (Mac48Address::ConvertFrom (to)); + hdr.SetLengthType (protocol); + packet->AddHeader (hdr); + + Ptr click = DynamicCast (GetRoutingProtocol ()); + click->Receive (packet->Copy (), Mac48Address::ConvertFrom (device->GetAddress ()), Mac48Address::ConvertFrom (to)); +} + +void +Ipv4L3ClickProtocol::LocalDeliver (Ptr packet, Ipv4Header const&ip, uint32_t iif) +{ + NS_LOG_FUNCTION (this << packet << &ip); + Ptr p = packet->Copy (); // need to pass a non-const packet up + + m_localDeliverTrace (ip, packet, iif); + + Ptr protocol = GetProtocol (ip.GetProtocol ()); + if (protocol != 0) + { + // we need to make a copy in the unlikely event we hit the + // RX_ENDPOINT_UNREACH codepath + Ptr copy = p->Copy (); + enum Ipv4L4Protocol::RxStatus status = + protocol->Receive (p, ip, GetInterface (iif)); + switch (status) { + case Ipv4L4Protocol::RX_OK: + // fall through + case Ipv4L4Protocol::RX_ENDPOINT_CLOSED: + // fall through + case Ipv4L4Protocol::RX_CSUM_FAILED: + break; + case Ipv4L4Protocol::RX_ENDPOINT_UNREACH: + if (ip.GetDestination ().IsBroadcast () == true || + ip.GetDestination ().IsMulticast () == true) + { + break; // Do not reply to broadcast or multicast + } + // Another case to suppress ICMP is a subnet-directed broadcast + bool subnetDirected = false; + for (uint32_t i = 0; i < GetNAddresses (iif); i++) + { + Ipv4InterfaceAddress addr = GetAddress (iif, i); + if (addr.GetLocal ().CombineMask (addr.GetMask ()) == ip.GetDestination().CombineMask (addr.GetMask ()) && + ip.GetDestination ().IsSubnetDirectedBroadcast (addr.GetMask ())) + { + subnetDirected = true; + } + } + if (subnetDirected == false) + { + GetIcmp ()->SendDestUnreachPort (ip, copy); + } + } + } +} + +Ptr +Ipv4L3ClickProtocol::GetIcmp (void) const +{ + Ptr prot = GetProtocol (Icmpv4L4Protocol::GetStaticProtocolNumber ()); + if (prot != 0) + { + return prot->GetObject (); + } + else + { + return 0; + } +} + +void +Ipv4L3ClickProtocol::Insert(Ptr protocol) +{ + m_protocols.push_back (protocol); +} + +Ptr +Ipv4L3ClickProtocol::GetProtocol(int protocolNumber) const +{ + for (L4List_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) + { + if ((*i)->GetProtocolNumber () == protocolNumber) + { + return *i; + } + } + return 0; +} + + +} // namespace ns3 + +#endif // NS3_CLICK diff --git a/src/routing/click/model/ipv4-l3-click-protocol.h b/src/routing/click/model/ipv4-l3-click-protocol.h new file mode 100644 index 000000000..399c1b2eb --- /dev/null +++ b/src/routing/click/model/ipv4-l3-click-protocol.h @@ -0,0 +1,270 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// +// 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: George F. Riley +// Author: Lalith Suresh +// + +#ifndef IPV4_L3_CLICK_PROTOCOL_H +#define IPV4_L3_CLICK_PROTOCOL_H + +#include "ns3/ipv4.h" +#include "ns3/net-device.h" +#include "ns3/packet.h" +#include "ns3/ipv4-routing-protocol.h" +#include "ns3/traced-callback.h" +#include "ns3/ipv4-interface.h" +#include "ns3/log.h" + +namespace ns3 { + +class Packet; +class NetDevice; +class Ipv4Interface; +class Ipv4Address; +class Ipv4Header; +class Ipv4RoutingTableEntry; +class Ipv4Route; +class Node; +class Socket; +class Ipv4RawSocketImpl; +class Ipv4L4Protocol; +class Icmpv4L4Protocol; + +/** + * \brief Implement the Ipv4 layer specifically for Click nodes + * to allow a clean integration of Click. + * + * This is code is mostly repeated from the Ipv4L3Protocol implementation. + * Changes include: + * - A stripped down version of Send(). + * - A stripped down version of Receive(). + * - A public version of LocalDeliver(). + * - Modifications to AddInterface(). + */ + +class Ipv4L3ClickProtocol : public Ipv4 +{ +#ifdef NS3_CLICK +public: + static TypeId GetTypeId (void); + + /** + * Protocol number for Ipv4 L3 (0x0800). + */ + static const uint16_t PROT_NUMBER; + + Ipv4L3ClickProtocol(); + virtual ~Ipv4L3ClickProtocol(); + + /** + * \param protocol a template for the protocol to add to this L4 Demux. + * \returns the L4Protocol effectively added. + * + * Invoke Copy on the input template to get a copy of the input + * protocol which can be used on the Node on which this L4 Demux + * is running. The new L4Protocol is registered internally as + * a working L4 Protocol and returned from this method. + * The caller does not get ownership of the returned pointer. + */ + void Insert(Ptr protocol); + + /** + * \param protocolNumber number of protocol to lookup + * in this L4 Demux + * \returns a matching L4 Protocol + * + * This method is typically called by lower layers + * to forward packets up the stack to the right protocol. + * It is also called from NodeImpl::GetUdp for example. + */ + Ptr GetProtocol(int protocolNumber) const; + + /** + * \param ttl default ttl to use + * + * When we need to send an ipv4 packet, we use this default + * ttl value. + */ + void SetDefaultTtl (uint8_t ttl); + + /** + * \param packet packet to send + * \param source source address of packet + * \param destination address of packet + * \param protocol number of packet + * \param route route entry + * + * Higher-level layers call this method to send a packet + * to Click + */ + void Send (Ptr packet, Ipv4Address source, + Ipv4Address destination, uint8_t protocol, Ptr route); + + /** + * \param packet packet to send down the stack + * \param ifid interface to be used for sending down packet + * + * Ipv4ClickRouting calls this method to send a packet further + * down the stack + */ + void SendDown (Ptr packet, int ifid); + + /** + * Lower layer calls this method to send a packet to Click + * \param device network device + * \param p the packet + * \param protocol protocol value + * \param from address of the correspondant + * \param to address of the destination + * \param packetType type of the packet + */ + void Receive( Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType); + + /** + * Ipv4ClickRouting calls this to locally deliver a packet + * \param p the packet + * \param ip The Ipv4Header of the packet + * \param iif The interface on which the packet was received + */ + void LocalDeliver (Ptr p, Ipv4Header const&ip, uint32_t iif); + + /** + * Get a pointer to the i'th Ipv4Interface + * \param i index of interface, pointer to which is to be returned + * \returns Pointer to the i'th Ipv4Interface if any. + */ + Ptr GetInterface (uint32_t i) const; + + /** + * Adds an Ipv4Interface to the interfaces list + * \param interface Pointer to the Ipv4Interface to be added + * \returns Index of the device which was added + */ + uint32_t AddIpv4Interface (Ptr interface); + + /** + * Calls m_node = node and sets up Loopback if needed + * \param node Pointer to the node + */ + void SetNode (Ptr node); + + /** + * Returns the Icmpv4L4Protocol for the node + * \returns Icmpv4L4Protocol instance of the node + */ + Ptr GetIcmp (void) const; + + /** + * Sets up a Loopback device + */ + void SetupLoopback (void); + + /** + * Creates a raw-socket + * \returns Pointer to the created socket + */ + Ptr CreateRawSocket (void); + + /** + * Deletes a particular raw socket + * \param socket Pointer of socket to be deleted + */ + void DeleteRawSocket (Ptr socket); + + // functions defined in base class Ipv4 + void SetRoutingProtocol (Ptr routingProtocol); + Ptr GetRoutingProtocol (void) const; + + Ptr GetNetDevice (uint32_t i); + + uint32_t AddInterface (Ptr device); + uint32_t GetNInterfaces (void) const; + + int32_t GetInterfaceForAddress (Ipv4Address addr) const; + int32_t GetInterfaceForPrefix (Ipv4Address addr, Ipv4Mask mask) const; + int32_t GetInterfaceForDevice (Ptr device) const; + bool IsDestinationAddress (Ipv4Address address, uint32_t iif) const; + + bool AddAddress (uint32_t i, Ipv4InterfaceAddress address); + Ipv4InterfaceAddress GetAddress (uint32_t interfaceIndex, uint32_t addressIndex) const; + uint32_t GetNAddresses (uint32_t interface) const; + bool RemoveAddress (uint32_t interfaceIndex, uint32_t addressIndex); + Ipv4Address SelectSourceAddress (Ptr device, + Ipv4Address dst, Ipv4InterfaceAddress::InterfaceAddressScope_e scope); + + void SetMetric (uint32_t i, uint16_t metric); + uint16_t GetMetric (uint32_t i) const; + uint16_t GetMtu (uint32_t i) const; + bool IsUp (uint32_t i) const; + void SetUp (uint32_t i); + void SetDown (uint32_t i); + bool IsForwarding (uint32_t i) const; + void SetForwarding (uint32_t i, bool val); + void SetPromisc(uint32_t i); +protected: + + virtual void DoDispose (void); + /** + * This function will notify other components connected to the node that a new stack member is now connected + * This will be used to notify Layer 3 protocol of layer 4 protocol stack to connect them together. + */ + virtual void NotifyNewAggregate (); + +private: + Ipv4Header BuildHeader ( + Ipv4Address source, + Ipv4Address destination, + uint8_t protocol, + uint16_t payloadSize, + uint8_t ttl, + bool mayFragment); + + virtual void SetIpForward (bool forward); + virtual bool GetIpForward (void) const; + virtual void SetWeakEsModel (bool model); + virtual bool GetWeakEsModel (void) const; + + typedef std::vector > Ipv4InterfaceList; + typedef std::list > SocketList; + typedef std::list > L4List_t; + + Ptr m_routingProtocol; + bool m_ipForward; + bool m_weakEsModel; + L4List_t m_protocols; + Ipv4InterfaceList m_interfaces; + uint8_t m_defaultTtl; + uint16_t m_identification; + + Ptr m_node; + + TracedCallback, uint32_t> m_sendOutgoingTrace; + TracedCallback, uint32_t> m_unicastForwardTrace; + TracedCallback, uint32_t> m_localDeliverTrace; + + SocketList m_sockets; + + std::vector m_promiscDeviceList; + +#endif //NS3_CLICK +}; + +} //namespace ns3 + +#endif // IPV4_L3_CLICK_ROUTING_H diff --git a/src/routing/click/test/ipv4-click-routing-test.cc b/src/routing/click/test/ipv4-click-routing-test.cc new file mode 100644 index 000000000..8bf1fbb66 --- /dev/null +++ b/src/routing/click/test/ipv4-click-routing-test.cc @@ -0,0 +1,222 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2010 Lalith Suresh + * + * 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 + * + * Authors: Lalith Suresh + */ + +#ifdef NS3_CLICK + +#include "ns3/test.h" +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/ipv4-l3-protocol.h" +#include "ns3/simple-net-device.h" +#include "ns3/ipv4-click-routing.h" +#include "ns3/icmpv4-l4-protocol.h" +#include "ns3/arp-l3-protocol.h" + +#include + +namespace ns3 { + +static void +AddClickInternetStack (Ptr node) +{ + // Setup ArpL3Protocol + Ptr arp = CreateObject (); + node->AggregateObject (arp); + + // Setup Ipv4L3Protocol + Ptr ipv4l3 = CreateObject (); + node->AggregateObject (ipv4l3); + + // Setup Click instance + Ptr ipv4 = node->GetObject (); + Ptr click = CreateObject (); + click->SetClickFile ("examples/click/nsclick-lan-single-interface.click"); + ipv4->SetRoutingProtocol (click); +} + +static void +AddNetworkDevice (Ptr node, Mac48Address macaddr, Ipv4Address ipv4addr, Ipv4Mask ipv4mask) +{ + Ptr rxDev1; + + rxDev1 = CreateObject (); + rxDev1->SetAddress (Mac48Address(macaddr)); + node->AddDevice (rxDev1); + + Ptr ipv4 = node->GetObject (); + uint32_t netdev_idx = ipv4->AddInterface (rxDev1); + Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (ipv4addr, ipv4mask); + ipv4->AddAddress (netdev_idx, ipv4Addr); + ipv4->SetUp (netdev_idx); +} + +class ClickIfidFromNameTest : public TestCase +{ +public: + ClickIfidFromNameTest (); + virtual void DoRun (); +}; + +ClickIfidFromNameTest::ClickIfidFromNameTest () + : TestCase ("Test SIMCLICK_IFID_FROM_NAME") +{ +} + +void +ClickIfidFromNameTest::DoRun () +{ + Ptr node = CreateObject (); + AddClickInternetStack (node); + AddNetworkDevice (node, Mac48Address("00:00:00:00:00:01"), Ipv4Address ("10.1.1.1"), Ipv4Mask ("255.255.255.0")); + Ptr ipv4 = node->GetObject (); + Ptr click = DynamicCast (ipv4->GetRoutingProtocol ()); + click->DoStart (); + + int ret; + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "tap0"); + NS_TEST_EXPECT_MSG_EQ (ret, 0, "tap0 is interface 0"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "tun0"); + NS_TEST_EXPECT_MSG_EQ (ret, 0, "tun0 is interface 0"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "eth0"); + NS_TEST_EXPECT_MSG_EQ (ret, 1, "Eth0 is interface 1"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "tap1"); + NS_TEST_EXPECT_MSG_EQ (ret, 0, "tap1 is interface 0"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "tun1"); + NS_TEST_EXPECT_MSG_EQ (ret, 0, "tun1 is interface 0"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IFID_FROM_NAME, "eth1"); + NS_TEST_EXPECT_MSG_EQ (ret, -1, "No eth1 on node"); + +} + +class ClickIpMacAddressFromNameTest : public TestCase +{ +public: + ClickIpMacAddressFromNameTest (); + virtual void DoRun (); +}; + +ClickIpMacAddressFromNameTest::ClickIpMacAddressFromNameTest () + : TestCase ("Test SIMCLICK_IPADDR_FROM_NAME") +{ +} + +void +ClickIpMacAddressFromNameTest::DoRun () +{ + Ptr node = CreateObject (); + AddClickInternetStack (node); + AddNetworkDevice (node, Mac48Address("00:00:00:00:00:01"), Ipv4Address ("10.1.1.1"), Ipv4Mask ("255.255.255.0")); + AddNetworkDevice (node, Mac48Address("00:00:00:00:00:02"), Ipv4Address ("10.1.1.2"), Ipv4Mask ("255.255.255.0")); + Ptr ipv4 = node->GetObject (); + Ptr click = DynamicCast (ipv4->GetRoutingProtocol ()); + click->DoStart (); + + int ret = 0; + char *buf = NULL; + buf = new char [255]; + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IPADDR_FROM_NAME, "eth0", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp (buf, "10.1.1.1"), 0, "eth0 has IP 10.1.1.1"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_MACADDR_FROM_NAME, "eth0", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp (buf, "00:00:00:00:00:01"), 0, "eth0 has Mac Address 00:00:00:00:00:01"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IPADDR_FROM_NAME, "eth1", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp(buf, "10.1.1.2"), 0, "eth1 has IP 10.1.1.2"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_MACADDR_FROM_NAME, "eth1", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp (buf, "00:00:00:00:00:02"), 0, "eth0 has Mac Address 00:00:00:00:00:02"); + + // Not sure how to test the below case, because the Ipv4ClickRouting code is to ASSERT for such inputs + // ret = simclick_sim_command (click->m_simNode, SIMCLICK_IPADDR_FROM_NAME, "eth2", buf, 255); + // NS_TEST_EXPECT_MSG_EQ (buf, NULL, "No eth2"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IPADDR_FROM_NAME, "tap0", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp(buf, "127.0.0.1"), 0, "tun0 has IP 127.0.0.1"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_MACADDR_FROM_NAME, "tap0", buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp(buf, "00:00:00:00:00:00"), 0, "tun0 has IP 127.0.0.1"); + + delete [] buf; +} + +class ClickTrivialTest : public TestCase +{ +public: + ClickTrivialTest (); + virtual void DoRun (); +}; + +ClickTrivialTest::ClickTrivialTest () + : TestCase ("Test SIMCLICK_GET_NODE_NAME and SIMCLICK_IF_READY") +{ +} + +void +ClickTrivialTest::DoRun () +{ + Ptr node = CreateObject (); + AddClickInternetStack (node); + AddNetworkDevice (node, Mac48Address("00:00:00:00:00:01"), Ipv4Address ("10.1.1.1"), Ipv4Mask ("255.255.255.0")); + Ptr ipv4 = node->GetObject (); + Ptr click = DynamicCast (ipv4->GetRoutingProtocol ()); + click->SetNodeName ("myNode"); + click->DoStart (); + + int ret = 0; + char *buf = NULL; + buf = new char [255]; + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_GET_NODE_NAME, buf, 255); + NS_TEST_EXPECT_MSG_EQ (strcmp (buf, "myNode"), 0, "Node name is Node"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IF_READY, 0); + NS_TEST_EXPECT_MSG_EQ (ret, 1, "tap0 is ready"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IF_READY, 1); + NS_TEST_EXPECT_MSG_EQ (ret, 1, "eth0 is ready"); + + ret = simclick_sim_command (click->m_simNode, SIMCLICK_IF_READY, 2); + NS_TEST_EXPECT_MSG_EQ (ret, -1, "eth1 does not exist, so return -1"); + + delete [] buf; + ret = 1; +} + +class ClickIfidFromNameTestSuite : public TestSuite +{ +public: + ClickIfidFromNameTestSuite () : TestSuite ("routing-click", UNIT) + { + AddTestCase (new ClickTrivialTest); + AddTestCase (new ClickIfidFromNameTest); + AddTestCase (new ClickIpMacAddressFromNameTest); + } +} g_ipv4ClickRoutingTestSuite; + +} // namespace ns3 + +#endif // NS3_CLICK diff --git a/src/routing/click/waf b/src/routing/click/waf new file mode 100644 index 000000000..4283ec141 --- /dev/null +++ b/src/routing/click/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../../waf "$@" diff --git a/src/routing/click/wscript b/src/routing/click/wscript new file mode 100644 index 000000000..6a486508b --- /dev/null +++ b/src/routing/click/wscript @@ -0,0 +1,93 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +import os +import Options + + +def set_options(opt): + opt.add_option('--with-nsclick', + help=('Path to Click source for NS-3 Click Integration support'), + dest='with_nsclick', default=None) + +def configure(conf): + if Options.options.with_nsclick: + if os.path.isdir(Options.options.with_nsclick): + conf.check_message("libnsclick.so location", '', True, ("%s (given)" % Options.options.with_nsclick)) + conf.env['WITH_NSCLICK'] = os.path.abspath(Options.options.with_nsclick) + else: + nsclick_dir = os.path.join('..','click') + if os.path.isdir(nsclick_dir): + conf.check_message("click location", '', True, ("%s (guessed)" % nsclick_dir)) + conf.env['WITH_NSCLICK'] = os.path.abspath(nsclick_dir) + del nsclick_dir + if not conf.env['WITH_NSCLICK']: + conf.check_message("click location", '', False) + conf.report_optional_feature("nsclick", "NS-3 Click Integration", False, + "nsclick not enabled (see option --with-nsclick)") + return + + test_code = ''' +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int simclick_sim_send(simclick_node_t *sim,int ifid,int type, const unsigned char* data,int len,simclick_simpacketinfo *pinfo) +{ + return 0; +} + +int simclick_sim_command(simclick_node_t *sim, int cmd, ...) +{ + return 0; +} +#ifdef __cplusplus +} +#endif + +int main() +{ + return 0; +} +''' + conf.env['DL'] = conf.check(mandatory=True, lib='dl', define_name='DL', uselib='DL') + + conf.env.append_value('NS3_MODULE_PATH',os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'ns'))) + + conf.env['CPPPATH_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'include'))] + conf.env['LIBPATH_NSCLICK'] = [os.path.abspath(os.path.join(conf.env['WITH_NSCLICK'],'ns'))] + + conf.env['NSCLICK'] = conf.check(fragment=test_code, lib='nsclick', uselib='NSCLICK DL') + conf.report_optional_feature("nsclick", "NS-3 Click Integration", + conf.env['NSCLICK'], "nsclick library not found") + if conf.env['NSCLICK']: + conf.env.append_value('CXXDEFINES', 'NS3_CLICK') + conf.env.append_value('CPPPATH', conf.env['CPPPATH_NSCLICK']) + +def build(bld): + + module = bld.create_ns3_module('click', ['internet-stack', 'contrib']) + module.includes = '. CPPPATH_NSCLICK' + module.source = [ + 'model/ipv4-click-routing.cc', + 'model/ipv4-l3-click-protocol.cc', + 'test/ipv4-click-routing-test.cc', + 'helper/click-internet-stack-helper.cc', + ] + + if bld.env['NSCLICK'] and bld.env['DL']: + module.uselib = 'NSCLICK DL' + + headers = bld.new_task_gen('ns3header') + headers.module = 'click' + headers.source = [ + 'model/ipv4-click-routing.h', + 'model/ipv4-l3-click-protocol.h', + 'helper/click-internet-stack-helper.h', + ] + + if bld.env['ENABLE_EXAMPLES']: + bld.add_subdirs('examples')