Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
damn!
[simgrid.git] / src / s4u / s4u_as.cpp
1 /* Copyright (c) 2006-2014. 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 "xbt/log.h"
8
9 #include "simgrid/s4u/as.hpp"
10 #include "src/surf/surf_routing.hpp"
11 #include "src/surf/network_interface.hpp" // Link FIXME: move to proper header
12
13 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_as,"S4U autonomous systems");
14
15 namespace simgrid {
16   namespace s4u {
17
18     As::As(const char *name)
19     : name_(xbt_strdup(name))
20     {
21     }
22     void As::Seal()
23     {
24       sealed_ = true;
25     }
26     As::~As()
27     {
28       xbt_dict_cursor_t cursor = NULL;
29       char *key;
30       AS_t elem;
31       xbt_dict_foreach(children_, cursor, key, elem) {
32         delete (As*)elem;
33       }
34
35
36       xbt_dict_free(&children_);
37       xbt_dynar_free(&vertices_);
38       xbt_dynar_free(&upDownLinks);
39       for (auto &kv : bypassRoutes_)
40         delete kv.second;
41       xbt_free(name_);
42       delete netcard_;
43     }
44
45     xbt_dict_t As::children()
46     {
47       return children_;
48     }
49     char *As::name()
50     {
51       return name_;
52     }
53     As *As::father() {
54       return father_;
55     }
56
57     xbt_dynar_t As::hosts()
58     {
59       xbt_dynar_t res =  xbt_dynar_new(sizeof(sg_host_t), NULL);
60
61       for (unsigned int index = 0; index < xbt_dynar_length(vertices_); index++) {
62         simgrid::surf::NetCard *card = xbt_dynar_get_as(vertices_, index, simgrid::surf::NetCard*);
63         simgrid::s4u::Host     *host = simgrid::s4u::Host::by_name_or_null(card->name());
64         if (host!=NULL)
65           xbt_dynar_push(res, &host);
66       }
67       return res;
68     }
69
70     xbt_dynar_t As::getOneLinkRoutes() {
71       return NULL;
72     }
73
74     int As::addComponent(surf::NetCard *elm) {
75       xbt_dynar_push_as(vertices_, surf::NetCard*, elm);
76       return xbt_dynar_length(vertices_)-1;
77     }
78
79     void As::addRoute(sg_platf_route_cbarg_t /*route*/){
80       xbt_die("AS %s does not accept new routes (wrong class).",name_);
81     }
82
83     /** @brief Get the common ancestor and its first childs in each line leading to src and dst */
84     static void find_common_ancestors(surf::NetCard *src, surf::NetCard *dst,
85         /* OUT */ As **common_ancestor, As **src_ancestor, As **dst_ancestor)
86     {
87     #define ROUTING_HIERARCHY_MAXDEPTH 32     /* increase if it is not enough */
88       simgrid::s4u::As *path_src[ROUTING_HIERARCHY_MAXDEPTH];
89       simgrid::s4u::As *path_dst[ROUTING_HIERARCHY_MAXDEPTH];
90       int index_src = 0;
91       int index_dst = 0;
92       simgrid::s4u::As *current_src;
93       simgrid::s4u::As *current_dst;
94       simgrid::s4u::As *father;
95
96       /* (1) find the path to root of src and dst*/
97       simgrid::s4u::As *src_as = src->containingAS();
98       simgrid::s4u::As *dst_as = dst->containingAS();
99
100       xbt_assert(src_as, "Host %s must be in an AS", src->name());
101       xbt_assert(dst_as, "Host %s must be in an AS", dst->name());
102
103       /* (2) find the path to the root routing component */
104       for (simgrid::s4u::As *current = src_as; current != NULL; current = current->father()) {
105         xbt_assert(index_src < ROUTING_HIERARCHY_MAXDEPTH, "ROUTING_HIERARCHY_MAXDEPTH should be increased for element %s", src->name());
106         path_src[index_src++] = current;
107       }
108       for (simgrid::s4u::As *current = dst_as; current != NULL; current = current->father()) {
109         xbt_assert(index_dst < ROUTING_HIERARCHY_MAXDEPTH,"ROUTING_HIERARCHY_MAXDEPTH should be increased for path_dst");
110         path_dst[index_dst++] = current;
111       }
112
113       /* (3) find the common father.
114        * Before that, index_src and index_dst may be different, they both point to NULL in path_src/path_dst
115        * So we move them down simultaneously as long as they point to the same content.
116        */
117       do {
118         current_src = path_src[--index_src];
119         current_dst = path_dst[--index_dst];
120       } while (index_src > 0 && index_dst > 0 && current_src == current_dst);
121
122       /* (4) if we did not find a difference (index_src or index_dst went to 0), both elements are in the same AS */
123       if (current_src == current_dst)
124         father = current_src;
125       else // we found a difference
126         father = path_src[index_src + 1];
127
128       /* (5) result generation */
129       *common_ancestor = father;    /* the common father of src and dst */
130       *src_ancestor = current_src;  /* the first different father of src */
131       *dst_ancestor = current_dst;  /* the first different father of dst */
132     #undef ROUTING_HIERARCHY_MAXDEPTH
133     }
134
135
136     /* PRECONDITION: this is the common ancestor of src and dst */
137     std::vector<surf::Link*> *As::getBypassRoute(surf::NetCard *src, surf::NetCard *dst)
138     {
139       // If never set a bypass route return NULL without any further computations
140       XBT_DEBUG("generic_get_bypassroute from %s to %s", src->name(), dst->name());
141       if (bypassRoutes_.empty())
142         return nullptr;
143
144       std::vector<surf::Link*> *bypassedRoute = nullptr;
145
146       if(dst->containingAS() == this && src->containingAS() == this ){
147         if (bypassRoutes_.find({src->name(),dst->name()}) != bypassRoutes_.end()) {
148           bypassedRoute = bypassRoutes_.at({src->name(),dst->name()});
149           XBT_DEBUG("Found a bypass route with %zu links",bypassedRoute->size());
150         }
151         return bypassedRoute;
152       }
153
154       /* (2) find the path to the root routing component */
155       std::vector<As*> path_src;
156       As *current = src->containingAS();
157       while (current != NULL) {
158         path_src.push_back(current);
159         current = current->father_;
160       }
161
162       std::vector<As*> path_dst;
163       current = dst->containingAS();
164       while (current != NULL) {
165         path_dst.push_back(current);
166         current = current->father_;
167       }
168
169       /* (3) find the common father */
170       while (path_src.size() > 1 && path_dst.size() >1
171           && path_src.at(path_src.size() -1) == path_dst.at(path_dst.size() -1)) {
172         path_src.pop_back();
173         path_dst.pop_back();
174       }
175
176       int max_index_src = path_src.size() - 1;
177       int max_index_dst = path_dst.size() - 1;
178
179       int max_index = std::max(max_index_src, max_index_dst);
180
181       for (int max = 0; max <= max_index; max++) {
182         for (int i = 0; i < max; i++) {
183           if (i <= max_index_src && max <= max_index_dst) {
184             const std::pair<std::string, std::string> key = {path_src.at(i)->name_, path_dst.at(max)->name_};
185             if (bypassRoutes_.find(key) != bypassRoutes_.end())
186               bypassedRoute = bypassRoutes_.at(key);
187           }
188           if (bypassedRoute)
189             break;
190           if (max <= max_index_src && i <= max_index_dst) {
191             const std::pair<std::string, std::string> key = {path_src.at(max)->name_, path_dst.at(i)->name_};
192             if (bypassRoutes_.find(key) != bypassRoutes_.end())
193               bypassedRoute = bypassRoutes_.at(key);
194           }
195           if (bypassedRoute)
196             break;
197         }
198
199         if (bypassedRoute)
200           break;
201
202         if (max <= max_index_src && max <= max_index_dst) {
203           const std::pair<std::string, std::string> key = {path_src.at(max)->name_, path_dst.at(max)->name_};
204           if (bypassRoutes_.find(key) != bypassRoutes_.end())
205             bypassedRoute = bypassRoutes_.at(key);
206         }
207         if (bypassedRoute)
208           break;
209       }
210
211       return bypassedRoute;
212     }
213
214     void As::addBypassRoute(sg_platf_route_cbarg_t e_route){
215       const char *src = e_route->src;
216       const char *dst = e_route->dst;
217
218       /* Argument validity checks */
219       if (e_route->gw_dst) {
220         XBT_DEBUG("Load bypassASroute from %s@%s to %s@%s",
221             src, e_route->gw_src->name(), dst, e_route->gw_dst->name());
222         xbt_assert(!e_route->link_list->empty(), "Bypass route between %s@%s and %s@%s cannot be empty.",
223             src, e_route->gw_src->name(), dst, e_route->gw_dst->name());
224         xbt_assert(bypassRoutes_.find({src,dst}) == bypassRoutes_.end(), "The bypass route between %s@%s and %s@%s already exists.",
225             src, e_route->gw_src->name(), dst, e_route->gw_dst->name());
226       } else {
227         XBT_DEBUG("Load bypassRoute from %s to %s", src, dst);
228         xbt_assert(!e_route->link_list->empty(),                         "Bypass route between %s and %s cannot be empty.",    src, dst);
229         xbt_assert(bypassRoutes_.find({src,dst}) == bypassRoutes_.end(), "The bypass route between %s and %s already exists.", src, dst);
230       }
231
232       /* Build a copy that will be stored in the dict */
233       std::vector<surf::Link*> *newRoute = new std::vector<surf::Link*>();
234       for (auto link: *e_route->link_list)
235         newRoute->push_back(link);
236
237       /* Store it */
238       bypassRoutes_.insert({{src,dst}, newRoute});
239     }
240
241     /**
242      * \brief Recursive function for getRouteAndLatency
243      *
244      * \param src the source host
245      * \param dst the destination host
246      * \param links Where to store the links and the gw information
247      * \param latency If not NULL, the latency of all links will be added in it
248      */
249     void As::getRouteRecursive(surf::NetCard *src, surf::NetCard *dst,
250         /* OUT */ std::vector<surf::Link*> * links, double *latency)
251     {
252       s_sg_platf_route_cbarg_t route;
253       memset(&route,0,sizeof(route));
254
255       XBT_DEBUG("Solve route/latency \"%s\" to \"%s\"", src->name(), dst->name());
256
257       /* Find how src and dst are interconnected */
258       simgrid::s4u::As *common_ancestor, *src_ancestor, *dst_ancestor;
259       find_common_ancestors(src, dst, &common_ancestor, &src_ancestor, &dst_ancestor);
260       XBT_DEBUG("elements_father: common ancestor '%s' src ancestor '%s' dst ancestor '%s'",
261           common_ancestor->name_, src_ancestor->name_, dst_ancestor->name_);
262
263       /* Check whether a direct bypass is defined. If so, use it and bail out */
264       std::vector<surf::Link*> *bypassed_route = common_ancestor->getBypassRoute(src, dst);
265       if (nullptr != bypassed_route) {
266         for (surf::Link *link : *bypassed_route) {
267           links->push_back(link);
268           if (latency)
269             *latency += link->getLatency();
270         }
271         return;
272       }
273
274       /* If src and dst are in the same AS, life is good */
275       if (src_ancestor == dst_ancestor) {       /* SURF_ROUTING_BASE */
276         route.link_list = links;
277         common_ancestor->getRouteAndLatency(src, dst, &route, latency);
278         return;
279       }
280
281       /* Not in the same AS, no bypass. We'll have to find our path between the ASes recursively*/
282
283       route.link_list = new std::vector<surf::Link*>();
284
285       common_ancestor->getRouteAndLatency(src_ancestor->netcard_, dst_ancestor->netcard_, &route, latency);
286       xbt_assert((route.gw_src != NULL) && (route.gw_dst != NULL),
287           "bad gateways for route from \"%s\" to \"%s\"", src->name(), dst->name());
288
289       /* If source gateway is not our source, we have to recursively find our way up to this point */
290       if (src != route.gw_src)
291         getRouteRecursive(src, route.gw_src, links, latency);
292       for (auto link: *route.link_list)
293         links->push_back(link);
294
295       /* If dest gateway is not our destination, we have to recursively find our way from this point */
296       if (route.gw_dst != dst)
297         getRouteRecursive(route.gw_dst, dst, links, latency);
298
299     }
300
301   }
302 };