+#ifdef HAVE_LATENCY_BOUND_TRACKING
+static int ns3_get_link_latency_limited(surf_action_t action)
+{
+ return 0;
+}
+#endif
+
+#ifdef HAVE_TRACING
+static void ns3_action_set_category(surf_action_t action, const char *category)
+{
+ action->category = xbt_strdup (category);
+}
+#endif
+
+void surf_network_model_init_NS3()
+{
+ if (surf_network_model)
+ return;
+
+ surf_network_model = surf_model_init();
+ surf_network_model->name = "network NS3";
+ surf_network_model->extension.network.get_link_latency = ns3_get_link_latency;
+ surf_network_model->extension.network.get_link_bandwidth = ns3_get_link_bandwidth;
+ surf_network_model->extension.network.get_route = ns3_get_route;
+
+ surf_network_model->model_private->share_resources = ns3_share_resources;
+ surf_network_model->model_private->update_actions_state = ns3_update_actions_state;
+ surf_network_model->model_private->finalize = finalize;
+
+ surf_network_model->suspend = action_suspend;
+ surf_network_model->resume = action_resume;
+ surf_network_model->is_suspended = action_is_suspended;
+ surf_network_model->action_unref = action_unref;
+ surf_network_model->extension.network.communicate = ns3_communicate;
+
+#ifdef HAVE_TRACING
+ surf_network_model->set_category = ns3_action_set_category;
+#endif
+
+ /* Added the initialization for NS3 interface */
+
+ if (ns3_initialize(xbt_cfg_get_string(_surf_cfg_set,"ns3/TcpModel"))) {
+ xbt_die("Impossible to initialize NS3 interface");
+ }
+
+ routing_model_create(sizeof(s_surf_ns3_link_t), NULL);
+ define_callbacks_ns3();
+
+ NS3_HOST_LEVEL = xbt_lib_add_level(host_lib,(void_f_pvoid_t)free_ns3_host);
+ NS3_ASR_LEVEL = xbt_lib_add_level(as_router_lib,(void_f_pvoid_t)free_ns3_host);
+ NS3_LINK_LEVEL = xbt_lib_add_level(link_lib,(void_f_pvoid_t)free_ns3_link);
+
+ xbt_dynar_push(model_list, &surf_network_model);
+
+#ifdef HAVE_LATENCY_BOUND_TRACKING
+ surf_network_model->get_latency_limited = ns3_get_link_latency_limited;
+#endif
+}
+
+static void finalize(void)
+{
+ ns3_finalize();
+ xbt_dynar_free_container(&IPV4addr);
+ xbt_dict_free(&dict_socket);
+}
+
+static double ns3_share_resources(double min)
+{
+ XBT_DEBUG("ns3_share_resources");
+
+ xbt_swag_t running_actions =
+ surf_network_model->states.running_action_set;
+
+ //get the first relevant value from the running_actions list
+ if (!xbt_swag_size(running_actions) || min == 0.0)
+ return -1.0;
+ else
+ do {
+ ns3_simulator(min);
+ time_to_next_flow_completion = ns3_time() - surf_get_clock();
+ } while(double_equals(time_to_next_flow_completion,0));
+
+ XBT_DEBUG("min : %f",min);
+ XBT_DEBUG("ns3 time : %f",ns3_time());
+ XBT_DEBUG("surf time : %f",surf_get_clock());
+ XBT_DEBUG("Next completion %f :",time_to_next_flow_completion);
+
+ return time_to_next_flow_completion;
+}
+
+static void ns3_update_actions_state(double now, double delta)
+{
+ xbt_dict_cursor_t cursor = NULL;
+ char *key;
+ void *data;
+
+ static xbt_dynar_t socket_to_destroy = NULL;
+ if(!socket_to_destroy) socket_to_destroy = xbt_dynar_new(sizeof(char*),NULL);
+
+ surf_action_network_ns3_t action = NULL;
+ xbt_swag_t running_actions =
+ surf_network_model->states.running_action_set;
+
+ /* If there are no running flows, just return */
+ if (!xbt_swag_size(running_actions)) {
+ while(double_positive(now-ns3_time())) {
+ ns3_simulator(now-ns3_time());
+ }
+ return;
+ }
+
+ xbt_dict_foreach(dict_socket,cursor,key,data){
+ action = (surf_action_network_ns3_t)ns3_get_socket_action(data);
+ XBT_DEBUG("Processing socket %p (action %p)",data,action);
+ action->generic_action.remains = action->generic_action.cost - ns3_get_socket_sent(data);
+
+#ifdef HAVE_TRACING
+ if (TRACE_is_enabled() &&
+ surf_action_state_get(&(action->generic_action)) == SURF_ACTION_RUNNING){
+ double data_sent = ns3_get_socket_sent(data);
+ double data_delta_sent = data_sent - action->last_sent;
+
+ xbt_dynar_t route = NULL;
+ routing_get_route_and_latency (action->src_name, action->dst_name, &route, NULL);
+ unsigned int i;
+ for (i = 0; i < xbt_dynar_length (route); i++){
+ surf_ns3_link_t *link = ((surf_ns3_link_t*)xbt_dynar_get_ptr (route, i));
+ TRACE_surf_link_set_utilization ((*link)->generic_resource.name,
+ ((surf_action_t) action)->category,
+ (data_delta_sent)/delta,
+ now-delta,
+ delta);
+ }
+ action->last_sent = data_sent;
+ }
+#endif
+
+ if(ns3_get_socket_is_finished(data) == 1){
+ xbt_dynar_push(socket_to_destroy,&key);
+ XBT_DEBUG("Destroy socket %p of action %p", key, action);
+ action->generic_action.finish = now;
+ surf_action_state_set(&(action->generic_action), SURF_ACTION_DONE);
+ }
+ }
+
+ while (!xbt_dynar_is_empty(socket_to_destroy)){
+ xbt_dynar_pop(socket_to_destroy,&key);
+
+ void *data = xbt_dict_get (dict_socket, key);
+ surf_action_network_ns3_t action = (surf_action_network_ns3_t)ns3_get_socket_action(data);
+ XBT_DEBUG ("Removing socket %p of action %p", key, action);
+ xbt_dict_remove(dict_socket,key);
+ }
+ return;
+}
+
+/* Max durations are not supported */
+static surf_action_t ns3_communicate(const char *src_name,
+ const char *dst_name, double size, double rate)
+{
+ surf_action_network_ns3_t action = NULL;
+
+ XBT_DEBUG("Communicate from %s to %s",src_name,dst_name);
+ action = surf_action_new(sizeof(s_surf_action_network_ns3_t), size, surf_network_model, 0);
+
+ ns3_create_flow(src_name, dst_name, surf_get_clock(), size, action);
+
+#ifdef HAVE_TRACING
+ action->last_sent = 0;
+ action->src_name = xbt_strdup (src_name);
+ action->dst_name = xbt_strdup (dst_name);
+#endif
+
+ return (surf_action_t) action;
+}
+
+/* Suspend a flow() */
+static void action_suspend(surf_action_t action)
+{
+ THROW_UNIMPLEMENTED;
+}
+
+/* Resume a flow() */
+static void action_resume(surf_action_t action)
+{
+ THROW_UNIMPLEMENTED;
+}
+
+/* Test whether a flow is suspended */
+static int action_is_suspended(surf_action_t action)
+{
+ return 0;
+}
+
+static int action_unref(surf_action_t action)
+{
+ action->refcount--;
+ if (!action->refcount) {
+ xbt_swag_remove(action, action->state_set);