Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
ac67a11792014b487710a97b77e319847f1232d4
[simgrid.git] / src / surf / network_ns3.cpp
1 /* Copyright (c) 2007-2017. The SimGrid Team. All rights reserved.          */
2
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. */
5
6 #include <unordered_set>
7
8 #include "xbt/config.hpp"
9
10 #include "ns3/core-module.h"
11 #include "ns3/node.h"
12
13 #include "ns3/ns3_simulator.h"
14 #include "network_ns3.hpp"
15
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"
18
19 #include "simgrid/s4u/Engine.hpp"
20 #include "simgrid/s4u/NetZone.hpp"
21
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ns3, surf, "Logging specific to the SURF network NS3 module");
23
24 std::vector<char*> IPV4addr;
25
26 /*****************
27  * Crude globals *
28  *****************/
29
30 extern xbt_dict_t flowFromSock;
31
32 static ns3::InternetStackHelper stack;
33 static ns3::NodeContainer nodes;
34 static ns3::NodeContainer Cluster_nodes;
35 static ns3::Ipv4InterfaceContainer interfaces;
36
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
42
43 simgrid::xbt::Extension<simgrid::kernel::routing::NetPoint, NetPointNs3> NetPointNs3::EXTENSION_ID;
44
45 NetPointNs3::NetPointNs3()
46 {
47   ns3::Ptr<ns3::Node> node = ns3::CreateObject<ns3::Node>(0);
48   stack.Install(node);
49   nodes.Add(node);
50   node_num = number_of_nodes++;
51 }
52
53 /*************
54  * Callbacks *
55  *************/
56
57 static void clusterCreation_cb(sg_platf_cluster_cbarg_t cluster)
58 {
59   char* lat = bprintf("%fs", cluster->lat);
60   char* bw  = bprintf("%fBps", cluster->bw);
61
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();
66
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);
71
72     ns3_add_link(host_src, host_dst, bw, lat);
73
74     delete host_dst;
75     free(host_id);
76   }
77   xbt_free(lat);
78   xbt_free(bw);
79
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);
84   xbt_free(lat);
85   xbt_free(bw);
86 }
87
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)
92 {
93   static bool warned_about_long_routes = false;
94
95   if (link_list->size() == 1) {
96     simgrid::surf::LinkNS3* link = static_cast<simgrid::surf::LinkNS3*>(link_list->at(0));
97
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());
102
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);
105
106     // create link ns3
107     NetPointNs3* host_src = src->extension<NetPointNs3>();
108     NetPointNs3* host_dst = dst->extension<NetPointNs3>();
109
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());
112
113     ns3_add_link(host_src, host_dst, link_bdw, link_lat);
114     if (symmetrical)
115       ns3_add_link(host_dst, host_src, link_bdw, link_lat);
116
117     xbt_free(link_bdw);
118     xbt_free(link_lat);
119   } else {
120     if (not warned_about_long_routes)
121       XBT_INFO(
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 "
125           "ignored.",
126           src->cname(), dst->cname(), link_list->size());
127     warned_about_long_routes = true;
128   }
129 }
130
131 /* Create the ns3 topology based on routing strategy */
132 static void postparse_cb(void)
133 {
134   IPV4addr.shrink_to_fit();
135
136   ns3::GlobalRouteManager::BuildGlobalRoutingDatabase();
137   ns3::GlobalRouteManager::InitializeRoutes();
138 }
139
140 /*********
141  * Model *
142  *********/
143 void surf_network_model_init_NS3()
144 {
145   if (surf_network_model)
146     return;
147
148   surf_network_model = new simgrid::surf::NetworkNS3Model();
149   all_existing_models->push_back(surf_network_model);
150 }
151
152 static simgrid::config::Flag<std::string> ns3_tcp_model("ns3/TcpModel",
153   "The ns3 tcp model can be : NewReno or Reno or Tahoe",
154   "default");
155
156 namespace simgrid {
157 namespace surf {
158
159 NetworkNS3Model::NetworkNS3Model() : NetworkModel() {
160   NetPointNs3::EXTENSION_ID = simgrid::kernel::routing::NetPoint::extension_create<NetPointNs3>();
161
162   ns3_initialize(ns3_tcp_model.get().c_str());
163
164   simgrid::kernel::routing::NetPoint::onCreation.connect([](simgrid::kernel::routing::NetPoint* pt) {
165     pt->extension_set<NetPointNs3>(new NetPointNs3());
166
167   });
168   simgrid::surf::on_cluster.connect(&clusterCreation_cb);
169   simgrid::s4u::onPlatformCreated.connect(&postparse_cb);
170   simgrid::s4u::NetZone::onRouteCreation.connect(&routeCreation_cb);
171
172   LogComponentEnable("UdpEchoClientApplication", ns3::LOG_LEVEL_INFO);
173   LogComponentEnable("UdpEchoServerApplication", ns3::LOG_LEVEL_INFO);
174 }
175
176 NetworkNS3Model::~NetworkNS3Model() {
177   for (auto addr : IPV4addr)
178     free(addr);
179   IPV4addr.clear();
180   xbt_dict_free(&flowFromSock);
181 }
182
183 LinkImpl* NetworkNS3Model::createLink(const char* name, double bandwidth, double latency,
184                                       e_surf_link_sharing_policy_t policy)
185 {
186   return new LinkNS3(this, name, bandwidth, latency);
187 }
188
189 Action* NetworkNS3Model::communicate(s4u::Host* src, s4u::Host* dst, double size, double rate)
190 {
191   return new NetworkNS3Action(this, size, src, dst);
192 }
193
194 double NetworkNS3Model::nextOccuringEvent(double now)
195 {
196   double time_to_next_flow_completion;
197   XBT_DEBUG("ns3_next_occuring_event");
198
199   //get the first relevant value from the running_actions list
200   if (!getRunningActionSet()->size() || now == 0.0)
201     return -1.0;
202   else
203     do {
204       ns3_simulator(now);
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));
207
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);
212
213   return time_to_next_flow_completion;
214 }
215
216 void NetworkNS3Model::updateActionsState(double now, double delta)
217 {
218   static xbt_dynar_t socket_to_destroy = xbt_dynar_new(sizeof(char*),nullptr);
219
220   /* If there are no running flows, advance the NS3 simulator and return */
221   if (getRunningActionSet()->empty()) {
222
223     while(double_positive(now - ns3::Simulator::Now().GetSeconds(), sg_surf_precision))
224       ns3_simulator(now-ns3::Simulator::Now().GetSeconds());
225
226     return;
227   }
228
229   xbt_dict_cursor_t cursor = nullptr;
230   char *ns3Socket;
231   SgFlow *sgFlow;
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_);
236
237     if (TRACE_is_enabled() &&
238         action->getState() == Action::State::running){
239       double data_delta_sent = sgFlow->sentBytes_ - action->lastSent_;
240
241       std::vector<LinkImpl*> route = std::vector<LinkImpl*>();
242
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,
246                                         delta);
247
248       action->lastSent_ = sgFlow->sentBytes_;
249     }
250
251     if(sgFlow->finished_){
252       xbt_dynar_push(socket_to_destroy,&ns3Socket);
253       XBT_DEBUG("Destroy socket %p of action %p", ns3Socket, action);
254       action->finish();
255       action->setState(Action::State::done);
256     }
257   }
258
259   while (!xbt_dynar_is_empty(socket_to_destroy)){
260     xbt_dynar_pop(socket_to_destroy,&ns3Socket);
261
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_);
265     }
266     xbt_dict_remove(flowFromSock, ns3Socket);
267   }
268 }
269
270 /************
271  * Resource *
272  ************/
273
274 LinkNS3::LinkNS3(NetworkNS3Model* model, const char* name, double bandwidth, double latency)
275     : LinkImpl(model, name, nullptr)
276 {
277   bandwidth_.peak = bandwidth;
278   latency_.peak   = latency;
279
280   s4u::Link::onCreation(this->piface_);
281 }
282
283 LinkNS3::~LinkNS3() = default;
284
285 void LinkNS3::apply_event(tmgr_trace_event_t event, double value)
286 {
287   THROW_UNIMPLEMENTED;
288 }
289 void LinkNS3::setBandwidthTrace(tmgr_trace_t trace) {
290   xbt_die("The NS3 network model doesn't support bandwidth traces");
291 }
292 void LinkNS3::setLatencyTrace(tmgr_trace_t trace) {
293   xbt_die("The NS3 network model doesn't support latency traces");
294 }
295
296 /**********
297  * Action *
298  **********/
299
300 NetworkNS3Action::NetworkNS3Action(Model* model, double size, s4u::Host* src, s4u::Host* dst)
301     : NetworkAction(model, size, false)
302 {
303   XBT_DEBUG("Communicate from %s to %s", src->cname(), dst->cname());
304
305   src_ = src;
306   dst_ = dst;
307   ns3_create_flow(src, dst, surf_get_clock(), size, this);
308
309   s4u::Link::onCommunicate(this, src, dst);
310 }
311
312 void NetworkNS3Action::suspend() {
313   THROW_UNIMPLEMENTED;
314 }
315
316 void NetworkNS3Action::resume() {
317   THROW_UNIMPLEMENTED;
318 }
319
320   /* Test whether a flow is suspended */
321 bool NetworkNS3Action::isSuspended()
322 {
323   return false;
324 }
325
326 int NetworkNS3Action::unref()
327 {
328   refcount_--;
329   if (!refcount_) {
330     if (action_hook.is_linked())
331       stateSet_->erase(stateSet_->iterator_to(*this));
332     XBT_DEBUG ("Removing action %p", this);
333     delete this;
334     return 1;
335   }
336   return 0;
337 }
338
339 }
340 }
341
342 void ns3_simulator(double maxSeconds)
343 {
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 ();
348 }
349
350 void ns3_create_flow(simgrid::s4u::Host* src, simgrid::s4u::Host* dst, double startTime, u_int32_t TotalBytes,
351                      simgrid::surf::NetworkNS3Action* action)
352 {
353   int node1 = src->pimpl_netpoint->extension<NetPointNs3>()->node_num;
354   int node2 = dst->pimpl_netpoint->extension<NetPointNs3>()->node_num;
355
356   ns3::Ptr<ns3::Node> src_node = nodes.Get(node1);
357   ns3::Ptr<ns3::Node> dst_node = nodes.Get(node2);
358
359   char* addr = IPV4addr.at(node2);
360
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);
364
365   ns3::Ptr<ns3::Socket> sock = ns3::Socket::CreateSocket (src_node, ns3::TcpSocketFactory::GetTypeId());
366
367   xbt_dict_set(flowFromSock, transformSocketPtr(sock), new SgFlow(TotalBytes, action), nullptr);
368
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);
372
373   ns3::Simulator::Schedule (ns3::Seconds(startTime-ns3::Simulator::Now().GetSeconds()),
374       &StartFlow, sock, addr, port_number);
375
376   port_number++;
377   xbt_assert(port_number <= 65000, "Too many connections! Port number is saturated.");
378 }
379
380 // initialize the NS3 interface and environment
381 void ns3_initialize(const char* TcpProtocol){
382 //  tcpModel are:
383 //  "ns3::TcpNewReno"
384 //  "ns3::TcpReno"
385 //  "ns3::TcpTahoe"
386
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));
389
390   if (!strcmp(TcpProtocol,"default"))
391     return;
392
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"));
396     return;
397   }
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"));
401     return;
402   }
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"));
406     return;
407   }
408
409   xbt_die("The ns3/TcpModel must be : NewReno or Reno or Tahoe");
410 }
411
412 void ns3_add_cluster(const char* id, char* bw, char* lat)
413 {
414   ns3::NodeContainer Nodes;
415
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);
419   }
420   number_of_clusters_nodes = Cluster_nodes.GetN();
421
422   XBT_DEBUG("Add router %d to cluster",nodes.GetN()-Nodes.GetN()-1);
423   Nodes.Add(nodes.Get(nodes.GetN()-Nodes.GetN()-1));
424
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");
431
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");
436   free(adr);
437   interfaces.Add(ipv4.Assign (devices));
438
439   if(number_of_links == 255){
440     xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
441     number_of_links = 1;
442     number_of_networks++;
443   }else{
444     number_of_links++;
445   }
446   XBT_DEBUG("Number of nodes in Cluster_nodes: %d",Cluster_nodes.GetN());
447 }
448
449 static char* transformIpv4Address (ns3::Ipv4Address from){
450   std::stringstream sstream;
451   sstream << from ;
452   std::string s = sstream.str();
453   return bprintf("%s",s.c_str());
454 }
455
456 void ns3_add_link(NetPointNs3* src, NetPointNs3* dst, char* bw, char* lat)
457 {
458   ns3::PointToPointHelper pointToPoint;
459
460   ns3::NetDeviceContainer netA;
461   ns3::Ipv4AddressHelper address;
462
463   int srcNum = src->node_num;
464   int dstNum = dst->node_num;
465
466   ns3::Ptr<ns3::Node> a = nodes.Get(srcNum);
467   ns3::Ptr<ns3::Node> b = nodes.Get(dstNum);
468
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));
472
473   netA.Add(pointToPoint.Install (a, b));
474
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);
478   free(adr);
479   interfaces.Add(address.Assign (netA));
480
481   if (IPV4addr.size() <= (unsigned)srcNum)
482     IPV4addr.resize(srcNum + 1, nullptr);
483   IPV4addr.at(srcNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 2));
484
485   if (IPV4addr.size() <= (unsigned)dstNum)
486     IPV4addr.resize(dstNum + 1, nullptr);
487   IPV4addr.at(dstNum) = transformIpv4Address(interfaces.GetAddress(interfaces.GetN() - 1));
488
489   if (number_of_links == 255){
490     xbt_assert(number_of_networks < 255, "Number of links and networks exceed 255*255");
491     number_of_links = 1;
492     number_of_networks++;
493   } else {
494     number_of_links++;
495   }
496 }