Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[surf] new (abstract) class: PropertyHolder, with only one purpose
[simgrid.git] / src / surf / network_ns3.cpp
1 /* Copyright (c) 2007-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "src/surf/network_ns3.hpp"
8 #include "src/surf/surf_private.h"
9 #include "src/surf/host_interface.hpp"
10 #include "simgrid/sg_config.h"
11
12 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(ns3);
13
14 xbt_dynar_t IPV4addr;
15 static double time_to_next_flow_completion = -1;
16
17 extern xbt_dict_t dict_socket;
18
19 /*************
20  * Callbacks *
21  *************/
22
23 static void replace_bdw_ns3(char ** bdw)
24 {
25   char *temp = xbt_strdup(*bdw);
26   xbt_free(*bdw);
27   *bdw = bprintf("%fBps",atof(temp));
28   xbt_free(temp);
29
30 }
31
32 static void replace_lat_ns3(char ** lat)
33 {
34   char *temp = xbt_strdup(*lat);
35   xbt_free(*lat);
36   *lat = bprintf("%fs",atof(temp));
37   xbt_free(temp);
38 }
39
40 static void simgrid_ns3_add_host(simgrid::surf::Host* host)
41 {
42   const char* id = host->getName();
43   XBT_DEBUG("NS3_ADD_HOST '%s'", id);
44   host->getHost()->set_facet(NS3_HOST_LEVEL, ns3_add_host(id));
45 }
46
47 static void parse_ns3_add_link(sg_platf_link_cbarg_t link)
48 {
49   XBT_DEBUG("NS3_ADD_LINK '%s'",link->id);
50
51   if(!IPV4addr) IPV4addr = xbt_dynar_new(sizeof(char*),free);
52
53   surf_network_model->createLink(link->id,
54                                      link->bandwidth,
55                                      link->bandwidth_trace,
56                                      link->latency,
57                                      link->latency_trace,
58                                      link->state,
59                                      link->state_trace,
60                                      link->policy,
61                                      link->properties);
62 }
63
64 static void simgrid_ns3_add_router(simgrid::surf::RoutingEdge* router)
65 {
66   const char* router_id = router->getName();
67   XBT_DEBUG("NS3_ADD_ROUTER '%s'",router_id);
68   xbt_lib_set(as_router_lib,
69               router_id,
70               NS3_ASR_LEVEL,
71               ns3_add_router(router_id)
72     );
73 }
74
75 static void parse_ns3_add_AS(simgrid::surf::As* as)
76 {
77   const char* as_id = as->p_name;
78   XBT_DEBUG("NS3_ADD_AS '%s'", as_id);
79   xbt_lib_set(as_router_lib, as_id, NS3_ASR_LEVEL, ns3_add_AS(as_id) );
80 }
81
82 static void parse_ns3_add_cluster(sg_platf_cluster_cbarg_t cluster)
83 {
84   const char *cluster_prefix = cluster->prefix;
85   const char *cluster_suffix = cluster->suffix;
86   const char *cluster_radical = cluster->radical;
87   const char *cluster_bb_bw = bprintf("%f",cluster->bb_bw);
88   const char *cluster_bb_lat = bprintf("%f",cluster->bb_lat);
89   const char *cluster_bw = bprintf("%f",cluster->bw);
90   const char *cluster_lat = bprintf("%f",cluster->lat);
91   const char *groups = NULL;
92
93   int start, end, i;
94   unsigned int iter;
95
96   xbt_dynar_t radical_elements;
97   xbt_dynar_t radical_ends;
98   xbt_dynar_t tab_elements_num = xbt_dynar_new(sizeof(int), NULL);
99
100   char *router_id,*host_id;
101
102   radical_elements = xbt_str_split(cluster_radical, ",");
103   xbt_dynar_foreach(radical_elements, iter, groups) {
104     radical_ends = xbt_str_split(groups, "-");
105
106     switch (xbt_dynar_length(radical_ends)) {
107     case 1:
108       start = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 0, char *));
109       xbt_dynar_push_as(tab_elements_num, int, start);
110       router_id = bprintf("ns3_%s%d%s", cluster_prefix, start, cluster_suffix);
111       simgrid::Host::by_name_or_create(router_id)
112         ->set_facet(NS3_HOST_LEVEL, ns3_add_host_cluster(router_id));
113       XBT_DEBUG("NS3_ADD_ROUTER '%s'",router_id);
114       free(router_id);
115       break;
116
117     case 2:
118       start = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 0, char *));
119       end = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 1, char *));
120       for (i = start; i <= end; i++){
121         xbt_dynar_push_as(tab_elements_num, int, i);
122         router_id = bprintf("ns3_%s%d%s", cluster_prefix, i, cluster_suffix);
123         simgrid::Host::by_name_or_create(router_id)
124           ->set_facet(NS3_HOST_LEVEL, ns3_add_host_cluster(router_id));
125         XBT_DEBUG("NS3_ADD_ROUTER '%s'",router_id);
126         free(router_id);
127       }
128       break;
129
130     default:
131       XBT_DEBUG("Malformed radical");
132     }
133   }
134
135   //Create links
136   unsigned int cpt;
137   int elmts;
138   char * lat = xbt_strdup(cluster_lat);
139   char * bw =  xbt_strdup(cluster_bw);
140   replace_lat_ns3(&lat);
141   replace_bdw_ns3(&bw);
142
143   xbt_dynar_foreach(tab_elements_num,cpt,elmts)
144   {
145     host_id   = bprintf("%s%d%s", cluster_prefix, elmts, cluster_suffix);
146     router_id = bprintf("ns3_%s%d%s", cluster_prefix, elmts, cluster_suffix);
147     XBT_DEBUG("Create link from '%s' to '%s'",host_id,router_id);
148
149     ns3_nodes_t host_src = ns3_find_host(host_id);
150     ns3_nodes_t host_dst = ns3_find_host(router_id);
151
152     if(host_src && host_dst){}
153     else xbt_die("\tns3_add_link from %d to %d",host_src->node_num,host_dst->node_num);
154
155     ns3_add_link(host_src->node_num,host_src->type,
156                  host_dst->node_num,host_dst->type,
157                  bw,lat);
158
159     free(router_id);
160     free(host_id);
161   }
162   xbt_dynar_free(&tab_elements_num);
163
164
165   //Create link backbone
166   lat = xbt_strdup(cluster_bb_lat);
167   bw =  xbt_strdup(cluster_bb_bw);
168   replace_lat_ns3(&lat);
169   replace_bdw_ns3(&bw);
170   ns3_add_cluster(bw,lat,cluster->id);
171   xbt_free(lat);
172   xbt_free(bw);
173 }
174
175 /* Create the ns3 topology based on routing strategy */
176 static void create_ns3_topology(void)
177 {
178   XBT_DEBUG("Starting topology generation");
179
180   xbt_dynar_shrink(IPV4addr,0);
181
182   //get the onelinks from the parsed platform
183   xbt_dynar_t onelink_routes = routing_platf->getOneLinkRoutes();
184   if (!onelink_routes)
185     xbt_die("There is no routes!");
186   XBT_DEBUG("Have get_onelink_routes, found %ld routes",onelink_routes->used);
187   //save them in trace file
188   simgrid::surf::Onelink *onelink;
189   unsigned int iter;
190   xbt_dynar_foreach(onelink_routes, iter, onelink) {
191     char *src = onelink->p_src->getName();
192     char *dst = onelink->p_dst->getName();
193     simgrid::surf::NetworkNS3Link *link =
194       static_cast<simgrid::surf::NetworkNS3Link *>(onelink->p_link);
195
196     if (strcmp(src,dst) && link->m_created){
197       XBT_DEBUG("Route from '%s' to '%s' with link '%s'", src, dst, link->getName());
198       char * link_bdw = xbt_strdup(link->p_bdw);
199       char * link_lat = xbt_strdup(link->p_lat);
200       replace_lat_ns3(&link_lat);
201       replace_bdw_ns3(&link_bdw);
202       link->m_created = 0;
203
204       //   XBT_DEBUG("src (%s), dst (%s), src_id = %d, dst_id = %d",src,dst, src_id, dst_id);
205       XBT_DEBUG("\tLink (%s) bdw:%s lat:%s", link->getName(), link_bdw, link_lat);
206
207       //create link ns3
208       ns3_nodes_t host_src = ns3_find_host(src);
209       if(!host_src) host_src = static_cast<ns3_nodes_t>(xbt_lib_get_or_null(as_router_lib,src,NS3_ASR_LEVEL));
210       ns3_nodes_t host_dst = ns3_find_host(dst);
211       if(!host_dst) host_dst = static_cast<ns3_nodes_t>(xbt_lib_get_or_null(as_router_lib,dst,NS3_ASR_LEVEL));
212
213       if(host_src && host_dst){}
214       else xbt_die("\tns3_add_link from %d to %d",host_src->node_num,host_dst->node_num);
215
216       ns3_add_link(host_src->node_num,host_src->type,host_dst->node_num,host_dst->type,link_bdw,link_lat);
217
218       xbt_free(link_bdw);
219       xbt_free(link_lat);
220     }
221   }
222 }
223
224 static void parse_ns3_end_platform(void)
225 {
226   ns3_end_platform();
227 }
228
229 static void define_callbacks_ns3(void)
230 {
231   simgrid::surf::hostCreatedCallbacks.connect(simgrid_ns3_add_host);
232   simgrid::surf::routingEdgeCreatedCallbacks.connect(simgrid_ns3_add_router);
233   sg_platf_link_add_cb (&parse_ns3_add_link);
234   sg_platf_cluster_add_cb (&parse_ns3_add_cluster);
235   simgrid::surf::asCreatedCallbacks.connect(parse_ns3_add_AS);
236   sg_platf_postparse_add_cb(&create_ns3_topology); //get_one_link_routes
237   sg_platf_postparse_add_cb(&parse_ns3_end_platform); //InitializeRoutes
238 }
239
240 /*********
241  * Model *
242  *********/
243 static void free_ns3_link(void * elmts)
244 {
245   delete static_cast<simgrid::surf::NetworkNS3Link*>(elmts);
246 }
247
248 static void free_ns3_host(void * elmts)
249 {
250   ns3_nodes_t host = static_cast<ns3_nodes_t>(elmts);
251   free(host);
252 }
253
254 void surf_network_model_init_NS3()
255 {
256   if (surf_network_model)
257     return;
258
259   surf_network_model = new simgrid::surf::NetworkNS3Model();
260
261   xbt_dynar_push(all_existing_models, &surf_network_model);
262 }
263
264 namespace simgrid {
265 namespace surf {
266
267 NetworkNS3Model::NetworkNS3Model() : NetworkModel() {
268   if (ns3_initialize(xbt_cfg_get_string(_sg_cfg_set, "ns3/TcpModel"))) {
269     xbt_die("Impossible to initialize NS3 interface");
270   }
271   routing_model_create(NULL);
272   define_callbacks_ns3();
273
274   NS3_HOST_LEVEL = simgrid::Host::add_level(free_ns3_host);
275   NS3_ASR_LEVEL  = xbt_lib_add_level(as_router_lib, free_ns3_host);
276 }
277
278 NetworkNS3Model::~NetworkNS3Model() {
279   ns3_finalize();
280   xbt_dynar_free_container(&IPV4addr);
281   xbt_dict_free(&dict_socket);
282 }
283
284 Link* NetworkNS3Model::createLink(const char *name,
285                                          double bw_initial,
286                                          tmgr_trace_t bw_trace,
287                                          double lat_initial,
288                                          tmgr_trace_t lat_trace,
289                                          e_surf_resource_state_t state_initial,
290                                          tmgr_trace_t state_trace,
291                                          e_surf_link_sharing_policy_t policy,
292                                          xbt_dict_t properties){
293   if (bw_trace)
294     XBT_INFO("The NS3 network model doesn't support bandwidth state traces");
295   if (lat_trace)
296     XBT_INFO("The NS3 network model doesn't support latency state traces");
297   if (state_trace)
298     XBT_INFO("The NS3 network model doesn't support link state traces");
299   Link* link = new NetworkNS3Link(this, name, properties, bw_initial, lat_initial);
300   surf_callback_emit(networkLinkCreatedCallbacks, link);
301   return link;
302 }
303
304 xbt_dynar_t NetworkNS3Model::getRoute(RoutingEdge *src, RoutingEdge *dst)
305 {
306   xbt_dynar_t route = NULL;
307   routing_get_route_and_latency(src, dst, &route, NULL);
308   //routing_platf->getRouteAndLatency(src, dst, &route, NULL);
309   return route;
310 }
311
312 Action *NetworkNS3Model::communicate(RoutingEdge *src, RoutingEdge *dst,
313                                                double size, double rate)
314 {
315   XBT_DEBUG("Communicate from %s to %s", src->getName(), dst->getName());
316   NetworkNS3Action *action = new NetworkNS3Action(this, size, 0);
317
318   ns3_create_flow(src->getName(), dst->getName(), surf_get_clock(), size, action);
319
320   action->m_lastSent = 0;
321   action->p_srcElm = src;
322   action->p_dstElm = dst;
323   surf_callback_emit(networkCommunicateCallbacks, action, src, dst, size, rate);
324
325   return (surf_action_t) action;
326 }
327
328 double NetworkNS3Model::shareResources(double now)
329 {
330   XBT_DEBUG("ns3_share_resources");
331
332   //get the first relevant value from the running_actions list
333   if (!getRunningActionSet()->size() || now == 0.0)
334     return -1.0;
335   else
336     do {
337       ns3_simulator(now);
338       time_to_next_flow_completion = ns3_time() - surf_get_clock();//FIXME: use now instead ?
339     } while(double_equals(time_to_next_flow_completion, 0, sg_surf_precision));
340
341   XBT_DEBUG("min       : %f", now);
342   XBT_DEBUG("ns3  time : %f", ns3_time());
343   XBT_DEBUG("surf time : %f", surf_get_clock());
344   XBT_DEBUG("Next completion %f :", time_to_next_flow_completion);
345
346   return time_to_next_flow_completion;
347 }
348
349 void NetworkNS3Model::updateActionsState(double now, double delta)
350 {
351   xbt_dict_cursor_t cursor = NULL;
352   char *key;
353   void *data;
354
355   static xbt_dynar_t socket_to_destroy = NULL;
356   if(!socket_to_destroy) socket_to_destroy = xbt_dynar_new(sizeof(char*),NULL);
357
358   /* If there are no running flows, just return */
359   if (!getRunningActionSet()->size()) {
360     while(double_positive(now-ns3_time(), sg_surf_precision)) {
361       ns3_simulator(now-ns3_time());
362     }
363     return;
364   }
365
366   NetworkNS3Action *action;
367   xbt_dict_foreach(dict_socket,cursor,key,data){
368     action = static_cast<NetworkNS3Action*>(ns3_get_socket_action(data));
369     XBT_DEBUG("Processing socket %p (action %p)",data,action);
370     action->setRemains(action->getCost() - ns3_get_socket_sent(data));
371
372     if (TRACE_is_enabled() &&
373                 action->getState() == SURF_ACTION_RUNNING){
374         double data_sent = ns3_get_socket_sent(data);
375         double data_delta_sent = data_sent - action->m_lastSent;
376
377         xbt_dynar_t route = NULL;
378
379         routing_get_route_and_latency (action->p_srcElm, action->p_dstElm, &route, NULL);
380         unsigned int i;
381         for (i = 0; i < xbt_dynar_length (route); i++){
382                 NetworkNS3Link* link = ((NetworkNS3Link*)xbt_dynar_get_ptr(route, i));
383                 TRACE_surf_link_set_utilization (link->getName(),
384                                 action->getCategory(),
385                                         (data_delta_sent)/delta,
386                                         now-delta,
387                                         delta);
388         }
389         action->m_lastSent = data_sent;
390     }
391
392     if(ns3_get_socket_is_finished(data) == 1){
393       xbt_dynar_push(socket_to_destroy,&key);
394       XBT_DEBUG("Destroy socket %p of action %p", key, action);
395       action->finish();
396       action->setState(SURF_ACTION_DONE);
397     }
398   }
399
400   while (!xbt_dynar_is_empty(socket_to_destroy)){
401     xbt_dynar_pop(socket_to_destroy,&key);
402
403     void *data = xbt_dict_get (dict_socket, key);
404     action = static_cast<NetworkNS3Action*>(ns3_get_socket_action(data));
405     XBT_DEBUG ("Removing socket %p of action %p", key, action);
406     xbt_dict_remove(dict_socket, key);
407   }
408   return;
409 }
410
411 /************
412  * Resource *
413  ************/
414
415 NetworkNS3Link::NetworkNS3Link(NetworkNS3Model *model, const char *name, xbt_dict_t props,
416                                        double bw_initial, double lat_initial)
417  : Link(model, name, props)
418  , p_lat(bprintf("%f", lat_initial))
419  , p_bdw(bprintf("%f", bw_initial))
420  , m_created(1)
421 {
422 }
423
424 NetworkNS3Link::~NetworkNS3Link()
425 {
426 }
427
428 void NetworkNS3Link::updateState(tmgr_trace_event_t event_type, double value, double date)
429 {
430
431 }
432
433 /**********
434  * Action *
435  **********/
436
437 NetworkNS3Action::NetworkNS3Action(Model *model, double cost, bool failed)
438 : NetworkAction(model, cost, failed)
439 {}
440
441 #ifdef HAVE_LATENCY_BOUND_TRACKING
442   int NetworkNS3Action::getLatencyLimited() {
443     return m_latencyLimited;
444   }
445 #endif
446
447  void NetworkNS3Action::suspend()
448 {
449   THROW_UNIMPLEMENTED;
450 }
451
452 void NetworkNS3Action::resume()
453 {
454   THROW_UNIMPLEMENTED;
455 }
456
457   /* Test whether a flow is suspended */
458 bool NetworkNS3Action::isSuspended()
459 {
460   return 0;
461 }
462
463 int NetworkNS3Action::unref()
464 {
465   m_refcount--;
466   if (!m_refcount) {
467         if (action_hook.is_linked())
468           p_stateSet->erase(p_stateSet->iterator_to(*this));
469     XBT_DEBUG ("Removing action %p", this);
470         delete this;
471     return 1;
472   }
473   return 0;
474 }
475
476 }
477 }