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 int node1 = src->pimpl_netpoint->extension<NetPointNs3>()->node_num;
354 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 char* addr = IPV4addr.at(node2);
361 XBT_DEBUG("ns3_create_flow %d Bytes from %d to %d with Interface %s",TotalBytes, node1, node2,addr);
362 ns3::PacketSinkHelper sink("ns3::TcpSocketFactory", ns3::InetSocketAddress (ns3::Ipv4Address::GetAny(), port_number));
363 sink.Install (dst_node);
365 ns3::Ptr<ns3::Socket> sock = ns3::Socket::CreateSocket (src_node, ns3::TcpSocketFactory::GetTypeId());
367 xbt_dict_set(flowFromSock, transformSocketPtr(sock), new SgFlow(TotalBytes, action), nullptr);
369 sock->Bind(ns3::InetSocketAddress(port_number));
370 XBT_DEBUG("Create flow starting to %fs + %fs = %fs",
371 startTime-ns3::Simulator::Now().GetSeconds(), ns3::Simulator::Now().GetSeconds(), startTime);
373 ns3::Simulator::Schedule (ns3::Seconds(startTime-ns3::Simulator::Now().GetSeconds()),
374 &StartFlow, sock, addr, port_number);
377 xbt_assert(port_number <= 65000, "Too many connections! Port number is saturated.");
380 // initialize the NS3 interface and environment
381 void ns3_initialize(const char* TcpProtocol){
387 ns3::Config::SetDefault ("ns3::TcpSocket::SegmentSize", ns3::UintegerValue (1024)); // 1024-byte packet for easier reading
388 ns3::Config::SetDefault ("ns3::TcpSocket::DelAckCount", ns3::UintegerValue (1));
390 if (!strcmp(TcpProtocol,"default"))
393 if (!strcmp(TcpProtocol,"Reno")) {
394 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
395 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpReno"));
398 if (!strcmp(TcpProtocol,"NewReno")) {
399 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
400 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpNewReno"));
403 if(!strcmp(TcpProtocol,"Tahoe")){
404 XBT_INFO("Switching Tcp protocol to '%s'",TcpProtocol);
405 ns3::Config::SetDefault ("ns3::TcpL4Protocol::SocketType", ns3::StringValue("ns3::TcpTahoe"));
409 xbt_die("The ns3/TcpModel must be : NewReno or Reno or Tahoe");
412 void ns3_add_cluster(const char* id, char* bw, char* lat)
414 ns3::NodeContainer Nodes;
416 for (unsigned int i = number_of_clusters_nodes; i < Cluster_nodes.GetN(); i++) {
417 Nodes.Add(Cluster_nodes.Get(i));
418 XBT_DEBUG("Add node %d to cluster",i);
420 number_of_clusters_nodes = Cluster_nodes.GetN();
422 XBT_DEBUG("Add router %d to cluster",nodes.GetN()-Nodes.GetN()-1);
423 Nodes.Add(nodes.Get(nodes.GetN()-Nodes.GetN()-1));
425 xbt_assert(Nodes.GetN() <= 65000, "Cluster with NS3 is limited to 65000 nodes");
426 ns3::CsmaHelper csma;
427 csma.SetChannelAttribute ("DataRate", ns3::StringValue (bw));
428 csma.SetChannelAttribute ("Delay", ns3::StringValue (lat));
429 ns3::NetDeviceContainer devices = csma.Install (Nodes);
430 XBT_DEBUG("Create CSMA");
432 char * adr = bprintf("%d.%d.0.0",number_of_networks,number_of_links);
433 XBT_DEBUG("Assign IP Addresses %s to CSMA.",adr);
434 ns3::Ipv4AddressHelper ipv4;
435 ipv4.SetBase (adr, "255.255.0.0");
437 interfaces.Add(ipv4.Assign (devices));
439 if(number_of_links == 255){
440 xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
442 number_of_networks++;
446 XBT_DEBUG("Number of nodes in Cluster_nodes: %d",Cluster_nodes.GetN());
449 static char* transformIpv4Address (ns3::Ipv4Address from){
450 std::stringstream sstream;
452 std::string s = sstream.str();
453 return bprintf("%s",s.c_str());
456 void ns3_add_link(NetPointNs3* src, NetPointNs3* dst, char* bw, char* lat)
458 ns3::PointToPointHelper pointToPoint;
460 ns3::NetDeviceContainer netA;
461 ns3::Ipv4AddressHelper address;
463 int srcNum = src->node_num;
464 int dstNum = dst->node_num;
466 ns3::Ptr<ns3::Node> a = nodes.Get(srcNum);
467 ns3::Ptr<ns3::Node> b = nodes.Get(dstNum);
469 XBT_DEBUG("\tAdd PTP from %d to %d bw:'%s' lat:'%s'", srcNum, dstNum, bw, lat);
470 pointToPoint.SetDeviceAttribute ("DataRate", ns3::StringValue (bw));
471 pointToPoint.SetChannelAttribute ("Delay", ns3::StringValue (lat));
473 netA.Add(pointToPoint.Install (a, b));
475 char * adr = bprintf("%d.%d.0.0",number_of_networks,number_of_links);
476 address.SetBase (adr, "255.255.0.0");
477 XBT_DEBUG("\tInterface stack '%s'",adr);
479 interfaces.Add(address.Assign (netA));
481 if (IPV4addr.size() <= (unsigned)srcNum)
482 IPV4addr.resize(srcNum + 1, nullptr);
483 IPV4addr.at(srcNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 2));
485 if (IPV4addr.size() <= (unsigned)dstNum)
486 IPV4addr.resize(dstNum + 1, nullptr);
487 IPV4addr.at(dstNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 1));
489 if (number_of_links == 255){
490 xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
492 number_of_networks++;