Using ns-3 from SimGrid
***********************
-The SimGrid/ns-3 binding only contains features that are common to both
-systems: ns-3 wireless models are not available, while SimGrid routes
-cannot be longer than 1. Also, the platform built in ns-3 from the
-SimGrid description is very basic.
+The SimGrid/ns-3 binding only contains features that are common to
+both systems. Not all ns-3 models are available (only the TCP and wifi
+ones are), while not all SimGrid platform file can be used with ns-3
+(routes must be of length 1). Also, the platform built in ns-3 from
+the SimGrid description is very basic.
Platform files compatibility
============================
.. code-block:: shell
- <platform>
- <zone id="zone0" routing="Full">
+ <?xml version='1.0'?>
+ <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
+ <platform version="4.1">
+ <zone id="zone0" routing="Floyd">
<host id="alice" speed="1Gf" />
<host id="bob" speed="1Gf" />
- <link id="l1" bw="1Mbps" />
- <link id="l2" bw="1Mbps" />
+ <link id="l1" bandwidth="1Mbps" latency="5ms" />
+ <link id="l2" bandwidth="1Mbps" latency="5ms" />
<route src="alice" dst="bob">
<link_ctn id="l1"/> <!-- !!!! INVALID WITH ns-3 !!!! -->
.. code-block:: shell
- <platform>
+ <?xml version='1.0'?>
+ <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
+ <platform version="4.1">
<zone id="zone0" routing="Full">
<host id="alice" speed="1Gf" />
<host id="bob" speed="1Gf" />
<router id="r1" /> <!-- routers are compute-less hosts -->
- <link id="l1" bw="1Mbps" />
- <link id="l2" bw="1Mbps" />
+ <link id="l1" bandwidth="1Mbps" latency="5ms"/>
+ <link id="l2" bandwidth="1Mbps" latency="5ms"/>
<route src="alice" dst="r1">
<link_ctn id="l1"/>
</platform>
Once your platform is OK, just change the :ref:`network/model
-<options_model_select>` configuration option to "ns-3" as follows. The rest
+<options_model_select>`_ configuration option to "ns-3" as follows. The rest
is unchanged.
.. code-block:: shell
Check the file `examples/s4u/network-ns3/network-ns3.tesh <https://framagit.org/simgrid/simgrid/tree/master/examples/s4u/network-ns3/network-ns3.tesh>`_
to see which ones are used in our regression tests.
+Build a wifi-compatible platform
+===================================
+
+We describe here a simple platform allowing ns3 wifi communication
+between two SimGrid hosts.
+
+First, here are the mandatory information necessary to create a
+simgrid platform:
+
+.. code-block:: shell
+
+ <?xml version='1.0'?>
+ <!DOCTYPE platform SYSTEM "http://simgrid.org/simgrid.dtd">
+ <platform version="4.1">
+ <zone id="zone" routing="Floyd">
+
+Then, we create our access point and station hosts:
+
+.. code-block:: shell
+
+ <host id="alice" speed="1Gf"/>
+ <host id="bob" speed="1Gf"/>
+
+We must specify that alice will be our access point. To do that we
+simply add the property ``wifi_link`` to the host ``alice``:
+
+.. code-block:: shell
+
+ <host id="alice" speed="1Gf">
+ <prop id="wifi_link" value="net0"/>
+ </host>
+
+ <host id="bob" speed="1Gf"/>
+
+The value ``net0`` of this property defines the name of the wifi network
+generated. To generate this wifi network we create a wifi link:
+
+.. code-block:: shell
+
+ <link id="net0" bandwidth="0" latency="0" sharing_policy="WIFI"/>
+
+The important information here are:
+ * The id of the link, ``net0``, must match the network name defined by the property ``wifi_link`` of the access point node
+ * The sharing policy must be set to ``WIFI``
+
+Note: bandwidth and latency are mandatory by simgrid to create a link but are NOT used to create a wifi network. Instead the
+wifi network capabilities are defined by its MCS, NSS and distance from access point to station. Those properties are described in section :ref:`Optional access point node properties <optional_prop>`_
+
+To connect the station node to the access point node, we
+create a route between the hosts:
+
+.. code-block:: shell
+
+ <route src="alice" dst="bob">
+ <link_ctn id="net0" />
+ </route>
+
+Finally, we end the xml file with the missing closing tags:
+
+.. code-block:: shell
+
+ </zone>
+ </platform>
+
+.. _optional_prop:
+
+Optional access point node properties
+--------------------------------------
+
+The MCS (`Modulation and Coding Scheme <https://en.wikipedia.org/wiki/Link_adaptation>`_) can be set with the property ``wifi_mcs``:
+
+.. code-block:: shell
+
+ <host id="alice" speed="1Gf">
+ <prop id="wifi_link" value="net0"/>
+ <prop id="wifi_mcs" value="5"/>
+ </host>
+
+Its default value is 3.
+
+The NSS (Number of Spatial Streams, also known as the `number of antennas <https://en.wikipedia.org/wiki/IEEE_802.11n-2009#Number_of_antennas>`_) can be set with the property ``wifi_nss``:
+
+.. code-block:: shell
+
+ <host id="alice" speed="1Gf">
+ <prop id="wifi_link" value="net0"/>
+ <prop id="wifi_nss" value="2"/>
+ </host>
+
+Its default value is 1.
+
+Note: not all value of MCS and NSS are valid nor compatible. Check `802.11n standard <https://en.wikipedia.org/wiki/IEEE_802.11n-2009#Data_rates>`_ for more information.
+
+Optional station node properties
+---------------------------------
+
+The distance in meter at which the station is placed from the access point can
+be set with the property ``wifi_distance``.
+
+.. code-block:: shell
+
+ <host id="alice" speed="100.0Mf,50.0Mf,20.0Mf" pstate="0">
+ <prop id="wifi_distance" value="30" />
+ </host>
+
+Its default value is 10.
+
Limitations
===========
A ns-3 platform is automatically created from the provided SimGrid
platform. However, there are some known caveats:
- * The default values (e.g., TCP parameters) are the ns-3 default values.
- * ns-3 networks are routed using the shortest path algorithm, using
- ``ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables``.
- * End hosts cannot have more than one interface card. So, your
- SimGrid hosts should be connected to the platform through only
- one link. Otherwise, your SimGrid host will be considered as a
- router.
-
+ * The default values (e.g., TCP parameters) are the ns-3 default values.
+ * ns-3 networks are routed using the shortest path algorithm, using
+ ``ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables``.
+ * End hosts cannot have more than one interface card. So, your
+ SimGrid hosts should be connected to the platform through only
+ one link. Otherwise, your SimGrid host will be considered as a
+ router (FIXME: is it still true?).
+
Our goal is to keep the ns-3 plugin of SimGrid as easy (and hopefully readable)
as possible. If the current state does not fit your needs, you should modify
this plugin, and/or create your own plugin from the existing one. If you come up
#include <ns3/application-container.h>
#include <ns3/event-id.h>
+#include "ns3/mobility-module.h"
+#include "ns3/wifi-module.h"
+
#include "network_ns3.hpp"
#include "ns3/ns3_simulator.hpp"
static int number_of_links = 1;
static int number_of_networks = 1;
+/* wifi globals */
+static ns3::WifiHelper wifi;
+static ns3::YansWifiPhyHelper wifiPhy = ns3::YansWifiPhyHelper::Default();
+static ns3::YansWifiChannelHelper wifiChannel = ns3::YansWifiChannelHelper::Default();
+static ns3::WifiMacHelper wifiMac;
+static ns3::MobilityHelper mobility;
+
simgrid::xbt::Extension<simgrid::kernel::routing::NetPoint, NetPointNs3> NetPointNs3::EXTENSION_ID;
+static std::string transformIpv4Address(ns3::Ipv4Address from)
+{
+ std::stringstream sstream;
+ sstream << from;
+ return sstream.str();
+}
+
NetPointNs3::NetPointNs3() : ns3_node_(ns3::CreateObject<ns3::Node>(0))
{
stack.Install(ns3_node_);
}
+WifiZone::WifiZone(std::string name_, simgrid::s4u::Host* host_, ns3::Ptr<ns3::Node> ap_node_,
+ ns3::Ptr<ns3::YansWifiChannel> channel_, int mcs_, int nss_, int network_, int link_)
+ : name(name_)
+ , host(host_)
+ , ap_node(ap_node_)
+ , channel(channel_)
+ , mcs(mcs_)
+ , nss(nss_)
+ , network(network_)
+ , link(link_)
+{
+ n_sta_nodes = 0;
+ wifi_zones[name_] = this;
+}
+
+bool WifiZone::is_ap(ns3::Ptr<ns3::Node> node)
+{
+ for (std::pair<std::string, WifiZone*> zone : wifi_zones)
+ if (zone.second->get_ap_node() == node)
+ return true;
+ return false;
+}
+
+WifiZone* WifiZone::by_name(std::string name)
+{
+ WifiZone* zone;
+ try {
+ zone = wifi_zones.at(name);
+ } catch (const std::out_of_range& oor) {
+ return nullptr;
+ }
+ return zone;
+}
+
+std::unordered_map<std::string, WifiZone*> WifiZone::wifi_zones;
+
+static void initialize_ns3_wifi()
+{
+ wifi.SetStandard(ns3::WIFI_PHY_STANDARD_80211n_5GHZ);
+
+ for (auto host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
+ const char* wifi_link = host->get_property("wifi_link");
+ const char* wifi_mcs = host->get_property("wifi_mcs");
+ const char* wifi_nss = host->get_property("wifi_nss");
+
+ if (wifi_link)
+ new WifiZone(wifi_link, host, host->get_netpoint()->extension<NetPointNs3>()->ns3_node_, wifiChannel.Create(),
+ wifi_mcs ? atoi(wifi_mcs) : 3, wifi_nss ? atoi(wifi_nss) : 1, 0, 0);
+ }
+}
+
/*************
* Callbacks *
*************/
auto* dst = simgrid::s4u::Engine::get_instance()->netpoint_by_name_or_null(cluster.router_id);
xbt_assert(dst != nullptr, "No router named %s", cluster.router_id.c_str());
- ns3_add_direct_route(src, dst, cluster.bw, cluster.lat, cluster.sharing_policy); // Any ns-3 route is symmetrical
+ ns3_add_direct_route(src, dst, cluster.bw, cluster.lat, cluster.id,
+ cluster.sharing_policy); // Any ns-3 route is symmetrical
// Also add the host to the list of hosts that will be connected to the backbone
Nodes.Add(src->extension<NetPointNs3>()->ns3_node_);
// XBT_DEBUG("src (%s), dst (%s), src_id = %d, dst_id = %d",src,dst, src_id, dst_id);
XBT_DEBUG("\tLink (%s) bw:%fbps lat:%fs", link->get_cname(), link->get_bandwidth(), link->get_latency());
- ns3_add_direct_route(src, dst, link->get_bandwidth(), link->get_latency(), link->get_sharing_policy());
+ ns3_add_direct_route(src, dst, link->get_bandwidth(), link->get_latency(), link->get_name(),
+ link->get_sharing_policy());
} else {
static bool warned_about_long_routes = false;
return -1.0;
XBT_DEBUG("doing a ns3 simulation for a duration of %f", now);
- ns3_simulator(now);
+ ns3_simulator(now);
time_to_next_flow_completion = ns3::Simulator::Now().GetSeconds() - surf_get_clock();
// NS-3 stops as soon as a flow ends,
// but it does not process the other flows that may finish at the same (simulated) time.
// If another flow ends at the same time, time_to_next_flow_completion = 0
if(double_equals(time_to_next_flow_completion, 0, sg_surf_precision))
- time_to_next_flow_completion = 0.0;
-
+ time_to_next_flow_completion = 0.0;
+
XBT_DEBUG("min : %f", now);
XBT_DEBUG("ns3 time : %f", ns3::Simulator::Now().GetSeconds());
XBT_DEBUG("surf time : %f", surf_get_clock());
/* If wifi, create the wifizone now. If not, don't do anything: the links will be created in routeCreate_cb */
+ if (policy == simgrid::s4u::Link::SharingPolicy::WIFI) {
+ static bool wifi_init = false;
+ if (!wifi_init) {
+ initialize_ns3_wifi();
+ wifi_init = true;
+ }
+
+ ns3::NetDeviceContainer netA;
+ WifiZone* zone = WifiZone::by_name(name);
+ xbt_assert(zone != 0, "Link name '%s' does not match the 'wifi_link' property of a host.", name.c_str());
+ NetPointNs3* netpoint_ns3 = zone->get_host()->get_netpoint()->extension<NetPointNs3>();
+
+ wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", "ControlMode", ns3::StringValue("HtMcs0"), "DataMode",
+ ns3::StringValue("HtMcs" + std::to_string(zone->get_mcs())));
+
+ wifiPhy.SetChannel(zone->get_channel());
+ wifiPhy.Set("Antennas", ns3::UintegerValue(zone->get_nss()));
+ wifiPhy.Set("MaxSupportedTxSpatialStreams", ns3::UintegerValue(zone->get_nss()));
+ wifiPhy.Set("MaxSupportedRxSpatialStreams", ns3::UintegerValue(zone->get_nss()));
+
+ wifiMac.SetType("ns3::ApWifiMac");
+
+ netA.Add(wifi.Install(wifiPhy, wifiMac, zone->get_ap_node()));
+
+ ns3::Ptr<ns3::ListPositionAllocator> positionAllocS = ns3::CreateObject<ns3::ListPositionAllocator>();
+ positionAllocS->Add(ns3::Vector(0, 0, 0));
+ mobility.SetPositionAllocator(positionAllocS);
+ mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+ mobility.Install(zone->get_ap_node());
+
+ ns3::Ipv4AddressHelper address;
+ std::string addr = simgrid::xbt::string_printf("%d.%d.0.0", number_of_networks, number_of_links);
+ address.SetBase(addr.c_str(), "255.255.0.0");
+ XBT_DEBUG("\tInterface stack '%s'", addr.c_str());
+ auto addresses = address.Assign(netA);
+ zone->set_network(number_of_networks);
+ zone->set_link(number_of_links);
+
+ netpoint_ns3->ipv4_address_ = transformIpv4Address(addresses.GetAddress(addresses.GetN() - 1));
+
+ if (number_of_links == 255) {
+ xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
+ number_of_links = 1;
+ number_of_networks++;
+ } else {
+ number_of_links++;
+ }
+ }
s4u::Link::on_creation(*this->get_iface());
}
void ns3_simulator(double maxSeconds)
{
- ns3::EventId id;
+ ns3::EventId id;
if (maxSeconds > 0.0) // If there is a maximum amount of time to run
id = ns3::Simulator::Schedule(ns3::Seconds(maxSeconds), &ns3::Simulator::Stop);
id.Cancel();
}
-static std::string transformIpv4Address(ns3::Ipv4Address from)
-{
- std::stringstream sstream;
- sstream << from ;
- return sstream.str();
-}
-
void ns3_add_direct_route(simgrid::kernel::routing::NetPoint* src, simgrid::kernel::routing::NetPoint* dst, double bw,
- double lat, simgrid::s4u::Link::SharingPolicy policy)
+ double lat, std::string link_name, simgrid::s4u::Link::SharingPolicy policy)
{
ns3::Ipv4AddressHelper address;
ns3::NetDeviceContainer netA;
xbt_assert(host_dst != nullptr, "Network element %s does not seem to be ns-3-ready", dst->get_cname());
if (policy == simgrid::s4u::Link::SharingPolicy::WIFI) {
- /* Install a ns3::WifiHelper */
+ auto a = host_src->ns3_node_;
+ auto b = host_dst->ns3_node_;
+ xbt_assert(WifiZone::is_ap(a) != WifiZone::is_ap(b),
+ "A wifi route can only exist between an access point node and a station node.");
+
+ ns3::Ptr<ns3::Node> apNode = WifiZone::is_ap(a) ? a : b;
+ ns3::Ptr<ns3::Node> staNode = apNode == a ? b : a;
+
+ WifiZone* zone = WifiZone::by_name(link_name);
+
+ wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", "ControlMode", ns3::StringValue("HtMcs0"), "DataMode",
+ ns3::StringValue("HtMcs" + std::to_string(zone->get_mcs())));
+
+ wifiPhy.SetChannel(zone->get_channel());
+ wifiPhy.Set("Antennas", ns3::UintegerValue(zone->get_nss()));
+ wifiPhy.Set("MaxSupportedTxSpatialStreams", ns3::UintegerValue(zone->get_nss()));
+ wifiPhy.Set("MaxSupportedRxSpatialStreams", ns3::UintegerValue(zone->get_nss()));
+
+ wifiMac.SetType("ns3::StaWifiMac");
+
+ netA.Add(wifi.Install(wifiPhy, wifiMac, staNode));
+
+ ns3::Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", ns3::UintegerValue(40));
+
+ NetPointNs3* sta_netpointNs3 = WifiZone::is_ap(host_src->ns3_node_) ? host_src : host_dst;
+ const char* wifi_distance = simgrid::s4u::Host::by_name(sta_netpointNs3->name_)->get_property("wifi_distance");
+ ns3::Ptr<ns3::ListPositionAllocator> positionAllocS = ns3::CreateObject<ns3::ListPositionAllocator>();
+ positionAllocS->Add(ns3::Vector(wifi_distance ? atof(wifi_distance) : 10.0, 0, 0));
+ mobility.SetPositionAllocator(positionAllocS);
+ mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+ mobility.Install(staNode);
+
+ std::string addr = simgrid::xbt::string_printf("%d.%d.0.0", zone->get_network(), zone->get_link());
+ address.SetBase(addr.c_str(), "255.255.0.0", ("0.0.0." + std::to_string(zone->get_n_sta_nodes() + 2)).c_str());
+ zone->add_sta_node();
+ XBT_DEBUG("\tInterface stack '%s'", addr.c_str());
+ auto addresses = address.Assign(netA);
+ host_dst->ipv4_address_ = transformIpv4Address(addresses.GetAddress(addresses.GetN() - 1));
} else {
ns3::PointToPointHelper pointToPoint;
pointToPoint.SetChannelAttribute("Delay", ns3::TimeValue(ns3::Seconds(lat)));
netA.Add(pointToPoint.Install(host_src->ns3_node_, host_dst->ns3_node_));
- }
- std::string addr = simgrid::xbt::string_printf("%d.%d.0.0", number_of_networks, number_of_links);
- address.SetBase(addr.c_str(), "255.255.0.0");
- XBT_DEBUG("\tInterface stack '%s'", addr.c_str());
- auto addresses = address.Assign(netA);
+ std::string addr = simgrid::xbt::string_printf("%d.%d.0.0", number_of_networks, number_of_links);
+ address.SetBase(addr.c_str(), "255.255.0.0");
+ XBT_DEBUG("\tInterface stack '%s'", addr.c_str());
+ auto addresses = address.Assign(netA);
- host_src->ipv4_address_ = transformIpv4Address(addresses.GetAddress(0));
- host_dst->ipv4_address_ = transformIpv4Address(addresses.GetAddress(1));
+ host_src->ipv4_address_ = transformIpv4Address(addresses.GetAddress(0));
+ host_dst->ipv4_address_ = transformIpv4Address(addresses.GetAddress(1));
- if (number_of_links == 255){
- xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
- number_of_links = 1;
- number_of_networks++;
- } else {
- number_of_links++;
+ if (number_of_links == 255) {
+ xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
+ number_of_links = 1;
+ number_of_networks++;
+ } else {
+ number_of_links++;
+ }
}
}
#include "simgrid/s4u/Host.hpp"
#include "src/surf/network_ns3.hpp"
+#include "ns3/wifi-module.h"
#include <ns3/node.h>
#include <ns3/tcp-socket-factory.h>
public:
static simgrid::xbt::Extension<simgrid::kernel::routing::NetPoint, NetPointNs3> EXTENSION_ID;
+ void set_name(std::string name) { name_ = name; }
+
explicit NetPointNs3();
+ std::string name_;
ns3::Ptr<ns3::Node> ns3_node_;
std::string ipv4_address_;
};
XBT_PRIVATE void ns3_initialize(std::string TcpProtocol);
XBT_PRIVATE void ns3_simulator(double max_seconds);
XBT_PRIVATE void ns3_add_direct_route(simgrid::kernel::routing::NetPoint* src, simgrid::kernel::routing::NetPoint* dst,
- double bw, double lat, simgrid::s4u::Link::SharingPolicy policy);
+ double bw, double lat, std::string link_name,
+ simgrid::s4u::Link::SharingPolicy policy);
class XBT_PRIVATE SgFlow {
public:
return sstream.str();
}
+class XBT_PRIVATE WifiZone {
+public:
+ WifiZone(std::string name_, simgrid::s4u::Host* host_, ns3::Ptr<ns3::Node> ap_node_,
+ ns3::Ptr<ns3::YansWifiChannel> channel_, int mcs_, int nss_, int network_, int link_);
+
+ const char* get_cname() { return name.c_str(); }
+ simgrid::s4u::Host* get_host() { return host; }
+ ns3::Ptr<ns3::Node> get_ap_node() { return ap_node; }
+ ns3::Ptr<ns3::YansWifiChannel> get_channel() { return channel; }
+ int get_mcs() { return mcs; }
+ int get_nss() { return nss; }
+ int get_network() { return network; }
+ int get_link() { return link; }
+ int get_n_sta_nodes() { return n_sta_nodes; }
+
+ void set_network(int network_) { network = network_; }
+ void set_link(int link_) { link = link_; }
+ void add_sta_node() { n_sta_nodes++; }
+
+ static bool is_ap(ns3::Ptr<ns3::Node> node);
+ static WifiZone* by_name(std::string name);
+
+private:
+ std::string name;
+ simgrid::s4u::Host* host;
+ ns3::Ptr<ns3::Node> ap_node;
+ ns3::Ptr<ns3::YansWifiChannel> channel;
+ int mcs;
+ int nss;
+ int network;
+ int link;
+ int n_sta_nodes = 0;
+ static std::unordered_map<std::string, WifiZone*> wifi_zones;
+};
+
#endif