Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
032e099b4bf422abb7dc994809c160b1beaeea11
[simgrid.git] / src / surf / network_ns3.c
1 /* Copyright (c) 2007, 2008, 2009, 2010, 2011. 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 "surf_private.h"
8 #include "surf/maxmin.h"
9 #include "surf/ns3/ns3_interface.h"
10 #include "xbt/lib.h"
11 #include "surf/network_ns3_private.h"
12 #include "xbt/str.h"
13
14 extern xbt_lib_t host_lib;
15 extern xbt_lib_t link_lib;
16 extern xbt_lib_t as_router_lib;
17
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_network_ns3, surf,
19                                 "Logging specific to the SURF network NS3 module");
20
21 extern routing_global_t global_routing;
22 extern xbt_dict_t dict_socket;
23
24 static double time_to_next_flow_completion = -1;
25
26 static double ns3_share_resources(double min);
27 static void ns3_update_actions_state(double now, double delta);
28 static void finalize(void);
29 static surf_action_t ns3_communicate(const char *src_name,
30                                  const char *dst_name, double size, double rate);
31 static void action_suspend(surf_action_t action);
32 static void action_resume(surf_action_t action);
33 static int action_is_suspended(surf_action_t action);
34 static int action_unref(surf_action_t action);
35
36 xbt_dynar_t IPV4addr;
37
38 static void replace_bdw_ns3(char ** bdw)
39 {
40         char *temp = xbt_strdup(*bdw);
41         xbt_free(*bdw);
42         *bdw = bprintf("%fBps",atof(temp));
43         xbt_free(temp);
44
45 }
46
47 static void replace_lat_ns3(char ** lat)
48 {
49         char *temp = xbt_strdup(*lat);
50         xbt_free(*lat);
51         *lat = bprintf("%fs",atof(temp));
52         xbt_free(temp);
53 }
54
55 static void parse_ns3_add_host(sg_platf_host_cbarg_t host)
56 {
57         XBT_DEBUG("NS3_ADD_HOST '%s'",A_surfxml_host_id);
58         xbt_lib_set(host_lib,
59                                 A_surfxml_host_id,
60                                 NS3_HOST_LEVEL,
61                                 ns3_add_host(A_surfxml_host_id)
62                                 );
63 }
64
65 static void ns3_free_dynar(void * elmts){
66         free(elmts);
67         return;
68 }
69
70 static void parse_ns3_add_link(sg_platf_link_cbarg_t l)
71 {
72         XBT_DEBUG("NS3_ADD_LINK '%s'",A_surfxml_link_id);
73
74         if(!IPV4addr) IPV4addr = xbt_dynar_new(sizeof(char*),ns3_free_dynar);
75
76         tmgr_trace_t bw_trace;
77         tmgr_trace_t state_trace;
78         tmgr_trace_t lat_trace;
79
80         bw_trace = tmgr_trace_new(A_surfxml_link_bandwidth_file);
81         lat_trace = tmgr_trace_new(A_surfxml_link_latency_file);
82         state_trace = tmgr_trace_new(A_surfxml_link_state_file);
83
84         if (bw_trace)
85                 XBT_INFO("The NS3 network model doesn't support bandwidth state traces");
86         if (lat_trace)
87                 XBT_INFO("The NS3 network model doesn't support latency state traces");
88         if (state_trace)
89                 XBT_INFO("The NS3 network model doesn't support link state traces");
90
91         ns3_link_t link_ns3 = xbt_new0(s_ns3_link_t,1);;
92         link_ns3->id = xbt_strdup(A_surfxml_link_id);
93         link_ns3->bdw = xbt_strdup(A_surfxml_link_bandwidth);
94         link_ns3->lat = xbt_strdup(A_surfxml_link_latency);
95
96         surf_ns3_link_t link = xbt_new0(s_surf_ns3_link_t,1);
97         link->generic_resource.name = xbt_strdup(A_surfxml_link_id);
98         link->generic_resource.properties = current_property_set;
99         link->data = link_ns3;
100         link->created = 1;
101
102         xbt_lib_set(link_lib,A_surfxml_link_id,NS3_LINK_LEVEL,link_ns3);
103         xbt_lib_set(link_lib,A_surfxml_link_id,SURF_LINK_LEVEL,link);
104 }
105
106 static void parse_ns3_add_router(sg_platf_router_cbarg_t router)
107 {
108         XBT_DEBUG("NS3_ADD_ROUTER '%s'",A_surfxml_router_id);
109         xbt_lib_set(as_router_lib,
110                                 A_surfxml_router_id,
111                                 NS3_ASR_LEVEL,
112                                 ns3_add_router(A_surfxml_router_id)
113                                 );
114 }
115
116 static void parse_ns3_add_AS(const char*id, const char*routing)
117 {
118         XBT_DEBUG("NS3_ADD_AS '%s'",A_surfxml_AS_id);
119         xbt_lib_set(as_router_lib,
120                                 A_surfxml_AS_id,
121                                 NS3_ASR_LEVEL,
122                                 ns3_add_AS(A_surfxml_AS_id)
123                                 );
124 }
125
126 static void parse_ns3_add_cluster(sg_platf_cluster_cbarg_t cluster)
127 {
128         char *cluster_prefix = A_surfxml_cluster_prefix;
129         char *cluster_suffix = A_surfxml_cluster_suffix;
130         char *cluster_radical = A_surfxml_cluster_radical;
131         char *cluster_bb_bw = A_surfxml_cluster_bb_bw;
132         char *cluster_bb_lat = A_surfxml_cluster_bb_lat;
133         char *cluster_bw = A_surfxml_cluster_bw;
134         char *cluster_lat = A_surfxml_cluster_lat;
135         char *groups = NULL;
136
137         int start, end, i;
138         unsigned int iter;
139
140         xbt_dynar_t radical_elements;
141         xbt_dynar_t radical_ends;
142         xbt_dynar_t tab_elements_num = xbt_dynar_new(sizeof(int), NULL);
143
144         char *router_id,*host_id;
145
146         radical_elements = xbt_str_split(cluster_radical, ",");
147         xbt_dynar_foreach(radical_elements, iter, groups) {
148                 radical_ends = xbt_str_split(groups, "-");
149
150                 switch (xbt_dynar_length(radical_ends)) {
151                 case 1:
152                   start = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 0, char *));
153                   xbt_dynar_push_as(tab_elements_num, int, start);
154                   router_id = bprintf("ns3_%s%d%s", cluster_prefix, start, cluster_suffix);
155                   xbt_lib_set(host_lib,
156                                                 router_id,
157                                                 NS3_HOST_LEVEL,
158                                                 ns3_add_host_cluster(router_id)
159                                                 );
160                   XBT_DEBUG("NS3_ADD_ROUTER '%s'",router_id);
161                   free(router_id);
162                   break;
163
164                 case 2:
165                   start = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 0, char *));
166                   end = surf_parse_get_int(xbt_dynar_get_as(radical_ends, 1, char *));
167                   for (i = start; i <= end; i++){
168                         xbt_dynar_push_as(tab_elements_num, int, i);
169                         router_id = bprintf("ns3_%s%d%s", cluster_prefix, i, cluster_suffix);
170                         xbt_lib_set(host_lib,
171                                                 router_id,
172                                                 NS3_HOST_LEVEL,
173                                                 ns3_add_host_cluster(router_id)
174                                                 );
175                         XBT_DEBUG("NS3_ADD_ROUTER '%s'",router_id);
176                         free(router_id);
177                   }
178                   break;
179
180                 default:
181                   XBT_DEBUG("Malformed radical");
182                 }
183         }
184
185         //Create links
186         unsigned int cpt;
187         int elmts;
188         char * lat = xbt_strdup(cluster_lat);
189         char * bw =  xbt_strdup(cluster_bw);
190         replace_lat_ns3(&lat);
191         replace_bdw_ns3(&bw);
192
193         xbt_dynar_foreach(tab_elements_num,cpt,elmts)
194         {
195                 host_id   = bprintf("%s%d%s", cluster_prefix, elmts, cluster_suffix);
196                 router_id = bprintf("ns3_%s%d%s", cluster_prefix, elmts, cluster_suffix);
197                 XBT_DEBUG("Create link from '%s' to '%s'",host_id,router_id);
198
199                 ns3_nodes_t host_src = xbt_lib_get_or_null(host_lib,host_id,  NS3_HOST_LEVEL);
200                 ns3_nodes_t host_dst = xbt_lib_get_or_null(host_lib,router_id,NS3_HOST_LEVEL);
201
202                 if(host_src && host_dst){}
203                 else xbt_die("\tns3_add_link from %d to %d",host_src->node_num,host_dst->node_num);
204
205                 ns3_add_link(host_src->node_num,host_src->type,
206                                          host_dst->node_num,host_dst->type,
207                                          bw,lat);
208
209                 free(router_id);
210                 free(host_id);
211         }
212         xbt_dynar_free(&tab_elements_num);
213
214
215         //Create link backbone
216         lat = xbt_strdup(cluster_bb_lat);
217         bw =  xbt_strdup(cluster_bb_bw);
218         replace_lat_ns3(&lat);
219         replace_bdw_ns3(&bw);
220         ns3_add_cluster(bw,lat,A_surfxml_cluster_id);
221         xbt_free(lat);
222         xbt_free(bw);   
223 }
224
225 static double ns3_get_link_latency (const void *link)
226 {
227         double lat;
228         //XBT_DEBUG("link_id:%s link_lat:%s link_bdw:%s",((surf_ns3_link_t)link)->data->id,((surf_ns3_link_t)link)->data->lat,((surf_ns3_link_t)link)->data->bdw);
229         sscanf(((surf_ns3_link_t)link)->data->lat,"%lg",&lat);
230         return lat;
231 }
232 static double ns3_get_link_bandwidth (const void *link)
233 {
234         double bdw;
235         //XBT_DEBUG("link_id:%s link_lat:%s link_bdw:%s",((surf_ns3_link_t)link)->data->id,((surf_ns3_link_t)link)->data->lat,((surf_ns3_link_t)link)->data->bdw);
236         sscanf(((surf_ns3_link_t)link)->data->bdw,"%lg",&bdw);
237         return bdw;
238 }
239
240 static xbt_dynar_t ns3_get_route(const char *src, const char *dst)
241 {
242   xbt_dynar_t route = NULL;
243   routing_get_route_and_latency(src, dst, &route, NULL);
244   return route;
245 }
246
247 static void parse_ns3_end_platform(void)
248 {
249         ns3_end_platform();
250 }
251
252 /* Create the ns3 topology based on routing strategy */
253 static void create_ns3_topology(void)
254 {
255    XBT_DEBUG("Starting topology generation");
256
257    xbt_dynar_shrink(IPV4addr,0);
258
259    //get the onelinks from the parsed platform
260    xbt_dynar_t onelink_routes = global_routing->get_onelink_routes();
261    if (!onelink_routes)
262      xbt_die("There is no routes!");
263    XBT_DEBUG("Have get_onelink_routes, found %ld routes",onelink_routes->used);
264    //save them in trace file
265    onelink_t onelink;
266    unsigned int iter;
267    xbt_dynar_foreach(onelink_routes, iter, onelink) {
268      char *src = onelink->src;
269      char *dst = onelink->dst;
270      void *link = onelink->link_ptr;
271
272      if( strcmp(src,dst) && ((surf_ns3_link_t)link)->created){
273      XBT_DEBUG("Route from '%s' to '%s' with link '%s'",src,dst,((surf_ns3_link_t)link)->data->id);
274      char * link_bdw = xbt_strdup(((surf_ns3_link_t)link)->data->bdw);
275          char * link_lat = xbt_strdup(((surf_ns3_link_t)link)->data->lat);
276          replace_lat_ns3(&link_lat);
277          replace_bdw_ns3(&link_bdw);
278          ((surf_ns3_link_t)link)->created = 0;
279
280          //      XBT_DEBUG("src (%s), dst (%s), src_id = %d, dst_id = %d",src,dst, src_id, dst_id);
281      XBT_DEBUG("\tLink (%s) bdw:%s lat:%s",((surf_ns3_link_t)link)->data->id,
282                  link_bdw,
283                  link_lat
284                  );
285
286      //create link ns3
287      ns3_nodes_t host_src = xbt_lib_get_or_null(host_lib,src,NS3_HOST_LEVEL);
288      if(!host_src) host_src = xbt_lib_get_or_null(as_router_lib,src,NS3_ASR_LEVEL);
289      ns3_nodes_t host_dst = xbt_lib_get_or_null(host_lib,dst,NS3_HOST_LEVEL);
290      if(!host_dst) host_dst = xbt_lib_get_or_null(as_router_lib,dst,NS3_ASR_LEVEL);
291
292      if(host_src && host_dst){}
293      else xbt_die("\tns3_add_link from %d to %d",host_src->node_num,host_dst->node_num);
294
295      ns3_add_link(host_src->node_num,host_src->type,host_dst->node_num,host_dst->type,link_bdw,link_lat);
296
297      xbt_free(link_bdw);
298      xbt_free(link_lat);
299      }
300    }
301 }
302
303 static void define_callbacks_ns3(void)
304 {
305   sg_platf_host_add_cb (&parse_ns3_add_host);
306   sg_platf_router_add_cb (&parse_ns3_add_router);
307   sg_platf_link_add_cb (&parse_ns3_add_link);
308   sg_platf_cluster_add_cb (&parse_ns3_add_cluster);
309   sg_platf_AS_begin_add_cb (&parse_ns3_add_AS);
310   sg_platf_postparse_add_cb(&create_ns3_topology); //get_one_link_routes
311   sg_platf_postparse_add_cb(&parse_ns3_end_platform); //InitializeRoutes
312 }
313
314 static void free_ns3_link(void * elmts)
315 {
316         ns3_link_t link = elmts;
317         free(link->id);
318         free(link->bdw);
319         free(link->lat);
320         free(link);
321 }
322
323 static void free_ns3_host(void * elmts)
324 {
325         ns3_nodes_t host = elmts;
326         free(host);
327 }
328
329 #ifdef HAVE_LATENCY_BOUND_TRACKING
330 static int ns3_get_link_latency_limited(surf_action_t action)
331 {
332   return 0;
333 }
334 #endif
335
336 #ifdef HAVE_TRACING
337 static void ns3_action_set_category(surf_action_t action, const char *category)
338 {
339   action->category = xbt_strdup (category);
340 }
341 #endif
342
343 void surf_network_model_init_NS3()
344 {
345         if (surf_network_model)
346                 return;
347
348         surf_network_model = surf_model_init();
349         surf_network_model->name = "network NS3";
350         surf_network_model->extension.network.get_link_latency = ns3_get_link_latency;
351         surf_network_model->extension.network.get_link_bandwidth = ns3_get_link_bandwidth;
352         surf_network_model->extension.network.get_route = ns3_get_route;
353
354         surf_network_model->model_private->share_resources = ns3_share_resources;
355         surf_network_model->model_private->update_actions_state = ns3_update_actions_state;
356         surf_network_model->model_private->finalize = finalize;
357
358         surf_network_model->suspend = action_suspend;
359         surf_network_model->resume = action_resume;
360         surf_network_model->is_suspended = action_is_suspended;
361         surf_network_model->action_unref = action_unref;
362         surf_network_model->extension.network.communicate = ns3_communicate;
363
364 #ifdef HAVE_TRACING
365   surf_network_model->set_category = ns3_action_set_category;
366 #endif
367
368         /* Added the initialization for NS3 interface */
369
370         if (ns3_initialize(xbt_cfg_get_string(_surf_cfg_set,"ns3/TcpModel"))) {
371         xbt_die("Impossible to initialize NS3 interface");
372         }
373
374         routing_model_create(sizeof(s_surf_ns3_link_t), NULL);
375         define_callbacks_ns3();
376
377         NS3_HOST_LEVEL = xbt_lib_add_level(host_lib,(void_f_pvoid_t)free_ns3_host);
378         NS3_ASR_LEVEL  = xbt_lib_add_level(as_router_lib,(void_f_pvoid_t)free_ns3_host);
379         NS3_LINK_LEVEL = xbt_lib_add_level(link_lib,(void_f_pvoid_t)free_ns3_link);
380
381         xbt_dynar_push(model_list, &surf_network_model);
382
383 #ifdef HAVE_LATENCY_BOUND_TRACKING
384         surf_network_model->get_latency_limited = ns3_get_link_latency_limited;
385 #endif
386 }
387
388 static void finalize(void)
389 {
390         ns3_finalize();
391         xbt_dynar_free_container(&IPV4addr);
392         xbt_dict_free(&dict_socket);
393 }
394
395 static double ns3_share_resources(double min)
396 {
397         XBT_DEBUG("ns3_share_resources");
398
399         xbt_swag_t running_actions =
400           surf_network_model->states.running_action_set;
401
402         //get the first relevant value from the running_actions list
403         if (!xbt_swag_size(running_actions) || min == 0.0)
404           return -1.0;
405         else
406          do {
407            ns3_simulator(min);
408            time_to_next_flow_completion = ns3_time() - surf_get_clock();
409          } while(double_equals(time_to_next_flow_completion,0));
410
411         XBT_DEBUG("min       : %f",min);
412         XBT_DEBUG("ns3  time : %f",ns3_time());
413         XBT_DEBUG("surf time : %f",surf_get_clock());
414         XBT_DEBUG("Next completion %f :",time_to_next_flow_completion);
415
416         return time_to_next_flow_completion;
417 }
418
419 static void ns3_update_actions_state(double now, double delta)
420 {
421           xbt_dict_cursor_t cursor = NULL;
422           char *key;
423           void *data;
424
425           static xbt_dynar_t socket_to_destroy = NULL;
426     if(!socket_to_destroy) socket_to_destroy = xbt_dynar_new(sizeof(char*),NULL);
427
428           surf_action_network_ns3_t action = NULL;
429           xbt_swag_t running_actions =
430               surf_network_model->states.running_action_set;
431
432           /* If there are no running flows, just return */
433           if (!xbt_swag_size(running_actions)) {
434             while(double_positive(now-ns3_time())) {
435               ns3_simulator(now-ns3_time());
436             }
437             return;
438           }
439
440           xbt_dict_foreach(dict_socket,cursor,key,data){
441             action = (surf_action_network_ns3_t)ns3_get_socket_action(data);
442             XBT_DEBUG("Processing socket %p (action %p)",data,action);
443             action->generic_action.remains = action->generic_action.cost - ns3_get_socket_sent(data);
444
445 #ifdef HAVE_TRACING
446             if (TRACE_is_enabled() &&
447                 surf_action_state_get(&(action->generic_action)) == SURF_ACTION_RUNNING){
448               double data_sent = ns3_get_socket_sent(data);
449               double data_delta_sent = data_sent - action->last_sent;
450
451               xbt_dynar_t route = NULL;
452               routing_get_route_and_latency (action->src_name, action->dst_name, &route, NULL);
453               unsigned int i;
454               for (i = 0; i < xbt_dynar_length (route); i++){
455                 surf_ns3_link_t *link = ((surf_ns3_link_t*)xbt_dynar_get_ptr (route, i));
456                 TRACE_surf_link_set_utilization ((*link)->generic_resource.name,
457                                                  ((surf_action_t) action)->category,
458                                                  (data_delta_sent)/delta,
459                                                  now-delta,
460                                                  delta);
461               }
462               action->last_sent = data_sent;
463             }
464 #endif
465
466             if(ns3_get_socket_is_finished(data) == 1){
467               xbt_dynar_push(socket_to_destroy,&key);
468               XBT_DEBUG("Destroy socket %p of action %p", key, action);
469               action->generic_action.finish = now;
470               surf_action_state_set(&(action->generic_action), SURF_ACTION_DONE);
471             }
472           }
473
474           while (!xbt_dynar_is_empty(socket_to_destroy)){
475             xbt_dynar_pop(socket_to_destroy,&key);
476
477             void *data = xbt_dict_get (dict_socket, key);
478             surf_action_network_ns3_t action = (surf_action_network_ns3_t)ns3_get_socket_action(data);
479             XBT_DEBUG ("Removing socket %p of action %p", key, action);
480             xbt_dict_remove(dict_socket,key);
481           }
482           return;
483 }
484
485 /* Max durations are not supported */
486 static surf_action_t ns3_communicate(const char *src_name,
487                                  const char *dst_name, double size, double rate)
488 {
489   surf_action_network_ns3_t action = NULL;
490
491   XBT_DEBUG("Communicate from %s to %s",src_name,dst_name);
492   action = surf_action_new(sizeof(s_surf_action_network_ns3_t), size, surf_network_model, 0);
493
494   ns3_create_flow(src_name, dst_name, surf_get_clock(), size, action);
495
496 #ifdef HAVE_TRACING
497   action->last_sent = 0;
498   action->src_name = xbt_strdup (src_name);
499   action->dst_name = xbt_strdup (dst_name);
500 #endif
501
502   return (surf_action_t) action;
503 }
504
505 /* Suspend a flow() */
506 static void action_suspend(surf_action_t action)
507 {
508   THROW_UNIMPLEMENTED;
509 }
510
511 /* Resume a flow() */
512 static void action_resume(surf_action_t action)
513 {
514   THROW_UNIMPLEMENTED;
515 }
516
517 /* Test whether a flow is suspended */
518 static int action_is_suspended(surf_action_t action)
519 {
520   return 0;
521 }
522
523 static int action_unref(surf_action_t action)
524 {
525   action->refcount--;
526   if (!action->refcount) {
527     xbt_swag_remove(action, action->state_set);
528
529 #ifdef HAVE_TRACING
530     xbt_free(((surf_action_network_ns3_t)action)->src_name);
531     xbt_free(((surf_action_network_ns3_t)action)->dst_name);
532     xbt_free(action->category);
533 #endif
534     XBT_DEBUG ("Removing action %p", action);
535     surf_action_free(&action);
536     return 1;
537   }
538   return 0;
539 }