1 /* Copyright (c) 2007-2017. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include <unordered_set>
8 #include "xbt/config.hpp"
10 #include "ns3/core-module.h"
13 #include "ns3/ns3_simulator.h"
14 #include "network_ns3.hpp"
16 #include "src/instr/instr_private.h" // TRACE_is_enabled(). FIXME: remove by subscribing tracing to the surf signals
17 #include "src/kernel/routing/NetPoint.hpp"
19 #include "simgrid/s4u/Engine.hpp"
20 #include "simgrid/s4u/NetZone.hpp"
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ns3, surf, "Logging specific to the SURF network NS3 module");
24 std::vector<char*> IPV4addr;
30 extern xbt_dict_t flowFromSock;
32 static ns3::InternetStackHelper stack;
33 static ns3::NodeContainer nodes;
34 static ns3::NodeContainer Cluster_nodes;
35 static ns3::Ipv4InterfaceContainer interfaces;
37 static int number_of_nodes = 0;
38 static int number_of_clusters_nodes = 0;
39 static int number_of_links = 1;
40 static int number_of_networks = 1;
41 static int port_number = 1025; //Port number is limited from 1025 to 65 000
43 simgrid::xbt::Extension<simgrid::kernel::routing::NetPoint, NetPointNs3> NetPointNs3::EXTENSION_ID;
45 NetPointNs3::NetPointNs3()
47 ns3::Ptr<ns3::Node> node = ns3::CreateObject<ns3::Node>(0);
50 node_num = number_of_nodes++;
57 static void clusterCreation_cb(sg_platf_cluster_cbarg_t cluster)
59 char* lat = bprintf("%fs", cluster->lat);
60 char* bw = bprintf("%fBps", cluster->bw);
62 for (int i : *cluster->radicals) {
63 // Routers don't create a router on the other end of the private link by themselves.
64 // We just need this router to be given an ID so we create a temporary NetPointNS3 so that it gets one
65 NetPointNs3* host_dst = new NetPointNs3();
67 // Create private link
68 char* host_id = bprintf("%s%d%s", cluster->prefix, i, cluster->suffix);
69 NetPointNs3* host_src = sg_host_by_name(host_id)->pimpl_netpoint->extension<NetPointNs3>();
70 xbt_assert(host_src, "Cannot find a NS3 host of name %s", host_id);
72 ns3_add_link(host_src, host_dst, bw, lat);
80 //Create link backbone
81 lat = bprintf("%fs", cluster->bb_lat);
82 bw = bprintf("%fBps", cluster->bb_bw);
83 ns3_add_cluster(cluster->id, bw, lat);
88 static void routeCreation_cb(bool symmetrical, simgrid::kernel::routing::NetPoint* src,
89 simgrid::kernel::routing::NetPoint* dst, simgrid::kernel::routing::NetPoint* gw_src,
90 simgrid::kernel::routing::NetPoint* gw_dst,
91 std::vector<simgrid::surf::LinkImpl*>* link_list)
93 static bool warned_about_long_routes = false;
95 if (link_list->size() == 1) {
96 simgrid::surf::LinkNS3* link = static_cast<simgrid::surf::LinkNS3*>(link_list->at(0));
98 XBT_DEBUG("Route from '%s' to '%s' with link '%s' %s", src->cname(), dst->cname(), link->cname(),
99 (symmetrical ? "(symmetrical)" : "(not symmetrical)"));
100 char* link_bdw = bprintf("%fBps", link->bandwidth());
101 char* link_lat = bprintf("%fs", link->latency());
103 // XBT_DEBUG("src (%s), dst (%s), src_id = %d, dst_id = %d",src,dst, src_id, dst_id);
104 XBT_DEBUG("\tLink (%s) bdw:%s lat:%s", link->cname(), link_bdw, link_lat);
107 NetPointNs3* host_src = src->extension<NetPointNs3>();
108 NetPointNs3* host_dst = dst->extension<NetPointNs3>();
110 xbt_assert(host_src != nullptr, "Network element %s does not seem to be NS3-ready", src->cname());
111 xbt_assert(host_dst != nullptr, "Network element %s does not seem to be NS3-ready", dst->cname());
113 ns3_add_link(host_src, host_dst, link_bdw, link_lat);
115 ns3_add_link(host_dst, host_src, link_bdw, link_lat);
120 if (not warned_about_long_routes)
122 "Ignoring a route between %s and %s of length %zu: Only routes of length 1 are considered with NS3.\n"
123 "You can ignore this warning if your hosts can still communicate when only considering routes of length 1.\n"
124 "You may also remove these routes to avoid this harmless message. Other long routes will be silently "
126 src->cname(), dst->cname(), link_list->size());
127 warned_about_long_routes = true;
131 /* Create the ns3 topology based on routing strategy */
132 static void postparse_cb(void)
134 IPV4addr.shrink_to_fit();
136 ns3::GlobalRouteManager::BuildGlobalRoutingDatabase();
137 ns3::GlobalRouteManager::InitializeRoutes();
143 void surf_network_model_init_NS3()
145 if (surf_network_model)
148 surf_network_model = new simgrid::surf::NetworkNS3Model();
149 all_existing_models->push_back(surf_network_model);
152 static simgrid::config::Flag<std::string> ns3_tcp_model("ns3/TcpModel",
153 "The ns3 tcp model can be : NewReno or Reno or Tahoe",
159 NetworkNS3Model::NetworkNS3Model() : NetworkModel() {
160 NetPointNs3::EXTENSION_ID = simgrid::kernel::routing::NetPoint::extension_create<NetPointNs3>();
162 ns3_initialize(ns3_tcp_model.get().c_str());
164 simgrid::kernel::routing::NetPoint::onCreation.connect([](simgrid::kernel::routing::NetPoint* pt) {
165 pt->extension_set<NetPointNs3>(new NetPointNs3());
168 simgrid::surf::on_cluster.connect(&clusterCreation_cb);
169 simgrid::s4u::onPlatformCreated.connect(&postparse_cb);
170 simgrid::s4u::NetZone::onRouteCreation.connect(&routeCreation_cb);
172 LogComponentEnable("UdpEchoClientApplication", ns3::LOG_LEVEL_INFO);
173 LogComponentEnable("UdpEchoServerApplication", ns3::LOG_LEVEL_INFO);
176 NetworkNS3Model::~NetworkNS3Model() {
177 for (auto addr : IPV4addr)
180 xbt_dict_free(&flowFromSock);
183 LinkImpl* NetworkNS3Model::createLink(const char* name, double bandwidth, double latency,
184 e_surf_link_sharing_policy_t policy)
186 return new LinkNS3(this, name, bandwidth, latency);
189 Action* NetworkNS3Model::communicate(s4u::Host* src, s4u::Host* dst, double size, double rate)
191 return new NetworkNS3Action(this, size, src, dst);
194 double NetworkNS3Model::nextOccuringEvent(double now)
196 double time_to_next_flow_completion;
197 XBT_DEBUG("ns3_next_occuring_event");
199 //get the first relevant value from the running_actions list
200 if (!getRunningActionSet()->size() || now == 0.0)
205 time_to_next_flow_completion = ns3::Simulator::Now().GetSeconds() - surf_get_clock();
206 } while(double_equals(time_to_next_flow_completion, 0, sg_surf_precision));
208 XBT_DEBUG("min : %f", now);
209 XBT_DEBUG("ns3 time : %f", ns3::Simulator::Now().GetSeconds());
210 XBT_DEBUG("surf time : %f", surf_get_clock());
211 XBT_DEBUG("Next completion %f :", time_to_next_flow_completion);
213 return time_to_next_flow_completion;
216 void NetworkNS3Model::updateActionsState(double now, double delta)
218 static xbt_dynar_t socket_to_destroy = xbt_dynar_new(sizeof(char*),nullptr);
220 /* If there are no running flows, advance the NS3 simulator and return */
221 if (getRunningActionSet()->empty()) {
223 while(double_positive(now - ns3::Simulator::Now().GetSeconds(), sg_surf_precision))
224 ns3_simulator(now-ns3::Simulator::Now().GetSeconds());
229 xbt_dict_cursor_t cursor = nullptr;
232 xbt_dict_foreach(flowFromSock,cursor,ns3Socket,sgFlow){
233 NetworkNS3Action * action = sgFlow->action_;
234 XBT_DEBUG("Processing socket %p (action %p)",sgFlow,action);
235 action->setRemains(action->getCost() - sgFlow->sentBytes_);
237 if (TRACE_is_enabled() &&
238 action->getState() == Action::State::running){
239 double data_delta_sent = sgFlow->sentBytes_ - action->lastSent_;
241 std::vector<LinkImpl*> route = std::vector<LinkImpl*>();
243 action->src_->routeTo(action->dst_, &route, nullptr);
244 for (auto link : route)
245 TRACE_surf_link_set_utilization(link->cname(), action->getCategory(), (data_delta_sent) / delta, now - delta,
248 action->lastSent_ = sgFlow->sentBytes_;
251 if(sgFlow->finished_){
252 xbt_dynar_push(socket_to_destroy,&ns3Socket);
253 XBT_DEBUG("Destroy socket %p of action %p", ns3Socket, action);
255 action->setState(Action::State::done);
259 while (!xbt_dynar_is_empty(socket_to_destroy)){
260 xbt_dynar_pop(socket_to_destroy,&ns3Socket);
262 if (XBT_LOG_ISENABLED(ns3, xbt_log_priority_debug)) {
263 SgFlow *flow = (SgFlow*)xbt_dict_get (flowFromSock, ns3Socket);
264 XBT_DEBUG ("Removing socket %p of action %p", ns3Socket, flow->action_);
266 xbt_dict_remove(flowFromSock, ns3Socket);
274 LinkNS3::LinkNS3(NetworkNS3Model* model, const char* name, double bandwidth, double latency)
275 : LinkImpl(model, name, nullptr)
277 bandwidth_.peak = bandwidth;
278 latency_.peak = latency;
280 s4u::Link::onCreation(this->piface_);
283 LinkNS3::~LinkNS3() = default;
285 void LinkNS3::apply_event(tmgr_trace_event_t event, double value)
289 void LinkNS3::setBandwidthTrace(tmgr_trace_t trace) {
290 xbt_die("The NS3 network model doesn't support bandwidth traces");
292 void LinkNS3::setLatencyTrace(tmgr_trace_t trace) {
293 xbt_die("The NS3 network model doesn't support latency traces");
300 NetworkNS3Action::NetworkNS3Action(Model* model, double size, s4u::Host* src, s4u::Host* dst)
301 : NetworkAction(model, size, false)
303 XBT_DEBUG("Communicate from %s to %s", src->cname(), dst->cname());
307 ns3_create_flow(src, dst, surf_get_clock(), size, this);
309 s4u::Link::onCommunicate(this, src, dst);
312 void NetworkNS3Action::suspend() {
316 void NetworkNS3Action::resume() {
320 /* Test whether a flow is suspended */
321 bool NetworkNS3Action::isSuspended()
326 int NetworkNS3Action::unref()
330 if (action_hook.is_linked())
331 stateSet_->erase(stateSet_->iterator_to(*this));
332 XBT_DEBUG ("Removing action %p", this);
342 void ns3_simulator(double maxSeconds)
344 if (maxSeconds > 0.0) // If there is a maximum amount of time to run
345 ns3::Simulator::Stop(ns3::Seconds(maxSeconds));
346 XBT_DEBUG("Start simulator for at most %fs (current time: %f)", maxSeconds, surf_get_clock());
347 ns3::Simulator::Run ();
350 void ns3_create_flow(simgrid::s4u::Host* src, simgrid::s4u::Host* dst, double startTime, u_int32_t TotalBytes,
351 simgrid::surf::NetworkNS3Action* action)
353 unsigned int node1 = src->pimpl_netpoint->extension<NetPointNs3>()->node_num;
354 unsigned int node2 = dst->pimpl_netpoint->extension<NetPointNs3>()->node_num;
356 ns3::Ptr<ns3::Node> src_node = nodes.Get(node1);
357 ns3::Ptr<ns3::Node> dst_node = nodes.Get(node2);
359 xbt_assert(node2 < IPV4addr.size(), "Element %s is unknown to NS3. Is it connected to any one-hop link?",
360 dst->pimpl_netpoint->cname());
361 char* addr = IPV4addr.at(node2);
362 xbt_assert(addr != nullptr, "Element %s is unknown to NS3. Is it connected to any one-hop link?",
363 dst->pimpl_netpoint->cname());
365 XBT_DEBUG("ns3_create_flow %d Bytes from %d to %d with Interface %s",TotalBytes, node1, node2,addr);
366 ns3::PacketSinkHelper sink("ns3::TcpSocketFactory", ns3::InetSocketAddress (ns3::Ipv4Address::GetAny(), port_number));
367 sink.Install (dst_node);
369 ns3::Ptr<ns3::Socket> sock = ns3::Socket::CreateSocket (src_node, ns3::TcpSocketFactory::GetTypeId());
371 xbt_dict_set(flowFromSock, transformSocketPtr(sock), new SgFlow(TotalBytes, action), nullptr);
373 sock->Bind(ns3::InetSocketAddress(port_number));
374 XBT_DEBUG("Create flow starting to %fs + %fs = %fs",
375 startTime-ns3::Simulator::Now().GetSeconds(), ns3::Simulator::Now().GetSeconds(), startTime);
377 ns3::Simulator::Schedule (ns3::Seconds(startTime-ns3::Simulator::Now().GetSeconds()),
378 &StartFlow, sock, addr, port_number);
381 xbt_assert(port_number <= 65000, "Too many connections! Port number is saturated.");
384 // initialize the NS3 interface and environment
385 void ns3_initialize(const char* TcpProtocol){
391 ns3::Config::SetDefault ("ns3::TcpSocket::SegmentSize", ns3::UintegerValue (1024)); // 1024-byte packet for easier reading
392 ns3::Config::SetDefault ("ns3::TcpSocket::DelAckCount", ns3::UintegerValue (1));
394 if (!strcmp(TcpProtocol,"default"))
397 if (!strcmp(TcpProtocol,"Reno")) {
398 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
399 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpReno"));
402 if (!strcmp(TcpProtocol,"NewReno")) {
403 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
404 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpNewReno"));
407 if(!strcmp(TcpProtocol,"Tahoe")){
408 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
409 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpTahoe"));
413 xbt_die("The ns3/TcpModel must be : NewReno or Reno or Tahoe");
416 void ns3_add_cluster(const char* id, char* bw, char* lat)
418 ns3::NodeContainer Nodes;
420 for (unsigned int i = number_of_clusters_nodes; i < Cluster_nodes.GetN(); i++) {
421 Nodes.Add(Cluster_nodes.Get(i));
422 XBT_DEBUG("Add node %d to cluster",i);
424 number_of_clusters_nodes = Cluster_nodes.GetN();
426 XBT_DEBUG("Add router %d to cluster",nodes.GetN()-Nodes.GetN()-1);
427 Nodes.Add(nodes.Get(nodes.GetN()-Nodes.GetN()-1));
429 xbt_assert(Nodes.GetN() <= 65000, "Cluster with NS3 is limited to 65000 nodes");
430 ns3::CsmaHelper csma;
431 csma.SetChannelAttribute ("DataRate", ns3::StringValue (bw));
432 csma.SetChannelAttribute ("Delay", ns3::StringValue (lat));
433 ns3::NetDeviceContainer devices = csma.Install (Nodes);
434 XBT_DEBUG("Create CSMA");
436 char * adr = bprintf("%d.%d.0.0",number_of_networks,number_of_links);
437 XBT_DEBUG("Assign IP Addresses %s to CSMA.",adr);
438 ns3::Ipv4AddressHelper ipv4;
439 ipv4.SetBase (adr, "255.255.0.0");
441 interfaces.Add(ipv4.Assign (devices));
443 if(number_of_links == 255){
444 xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
446 number_of_networks++;
450 XBT_DEBUG("Number of nodes in Cluster_nodes: %d",Cluster_nodes.GetN());
453 static char* transformIpv4Address (ns3::Ipv4Address from){
454 std::stringstream sstream;
456 std::string s = sstream.str();
457 return bprintf("%s",s.c_str());
460 void ns3_add_link(NetPointNs3* src, NetPointNs3* dst, char* bw, char* lat)
462 ns3::PointToPointHelper pointToPoint;
464 ns3::NetDeviceContainer netA;
465 ns3::Ipv4AddressHelper address;
467 int srcNum = src->node_num;
468 int dstNum = dst->node_num;
470 ns3::Ptr<ns3::Node> a = nodes.Get(srcNum);
471 ns3::Ptr<ns3::Node> b = nodes.Get(dstNum);
473 XBT_DEBUG("\tAdd PTP from %d to %d bw:'%s' lat:'%s'", srcNum, dstNum, bw, lat);
474 pointToPoint.SetDeviceAttribute ("DataRate", ns3::StringValue (bw));
475 pointToPoint.SetChannelAttribute ("Delay", ns3::StringValue (lat));
477 netA.Add(pointToPoint.Install (a, b));
479 char * adr = bprintf("%d.%d.0.0",number_of_networks,number_of_links);
480 address.SetBase (adr, "255.255.0.0");
481 XBT_DEBUG("\tInterface stack '%s'",adr);
483 interfaces.Add(address.Assign (netA));
485 if (IPV4addr.size() <= (unsigned)srcNum)
486 IPV4addr.resize(srcNum + 1, nullptr);
487 IPV4addr.at(srcNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 2));
489 if (IPV4addr.size() <= (unsigned)dstNum)
490 IPV4addr.resize(dstNum + 1, nullptr);
491 IPV4addr.at(dstNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 1));
493 if (number_of_links == 255){
494 xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
496 number_of_networks++;