Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' into MC_LTL
[simgrid.git] / src / surf / surf_routing_rulebased.c
1 /* Copyright (c) 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 #include "surf_routing_private.h"
7 #include <pcre.h>               /* regular expression library */
8
9 /* Global vars */
10 extern routing_global_t global_routing;
11 extern xbt_dynar_t parsed_link_list;
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_route_rulebased, surf, "Routing part of surf");
14
15 /* Routing model structure */
16
17 typedef struct {
18   s_as_t generic_routing;
19   xbt_dict_t dict_processing_units;
20   xbt_dict_t dict_autonomous_systems;
21   xbt_dynar_t list_route;
22   xbt_dynar_t list_ASroute;
23 } s_AS_rulebased_t, *AS_rulebased_t;
24
25 typedef struct s_rule_route s_rule_route_t, *rule_route_t;
26 typedef struct s_rule_route_extended s_rule_route_extended_t,
27     *rule_route_extended_t;
28
29 struct s_rule_route {
30   xbt_dynar_t re_str_link;      // dynar of char*
31   pcre *re_src;
32   pcre *re_dst;
33 };
34
35 struct s_rule_route_extended {
36   s_rule_route_t generic_rule_route;
37   char *re_src_gateway;
38   char *re_dst_gateway;
39 };
40
41 static void rule_route_free(void *e)
42 {
43   rule_route_t *elem = (rule_route_t *) (e);
44   if (*elem) {
45     xbt_dynar_free(&(*elem)->re_str_link);
46     pcre_free((*elem)->re_src);
47     pcre_free((*elem)->re_dst);
48     xbt_free(*elem);
49   }
50   *elem = NULL;
51 }
52
53 static void rule_route_extended_free(void *e)
54 {
55   rule_route_extended_t *elem = (rule_route_extended_t *) e;
56   if (*elem) {
57     xbt_dynar_free(&(*elem)->generic_rule_route.re_str_link);
58     pcre_free((*elem)->generic_rule_route.re_src);
59     pcre_free((*elem)->generic_rule_route.re_dst);
60     xbt_free((*elem)->re_src_gateway);
61     xbt_free((*elem)->re_dst_gateway);
62     xbt_free(*elem);
63   }
64 }
65
66 /* Parse routing model functions */
67
68 static void model_rulebased_parse_PU(AS_t rc, const char *name)
69 {
70   AS_rulebased_t routing = (AS_rulebased_t) rc;
71   xbt_dict_set(routing->dict_processing_units, name, (void *) (-1), NULL);
72 }
73
74 static void model_rulebased_parse_AS(AS_t rc, const char *name)
75 {
76   AS_rulebased_t routing = (AS_rulebased_t) rc;
77   xbt_dict_set(routing->dict_autonomous_systems, name, (void *) (-1), NULL);
78 }
79
80 static void model_rulebased_parse_route(AS_t rc,
81                                       const char *src, const char *dst,
82                                       route_t route)
83 {
84   AS_rulebased_t routing = (AS_rulebased_t) rc;
85   rule_route_t ruleroute = xbt_new0(s_rule_route_t, 1);
86   const char *error;
87   int erroffset;
88
89   if(!strcmp(rc->model_desc->name,"Vivaldi")){
90           if(!xbt_dynar_is_empty(route->link_list))
91                   xbt_die("You can't have link_ctn with Model Vivaldi.");
92   }
93
94   ruleroute->re_src = pcre_compile(src, 0, &error, &erroffset, NULL);
95   xbt_assert(ruleroute->re_src,
96               "PCRE compilation failed at offset %d (\"%s\"): %s\n",
97               erroffset, src, error);
98   ruleroute->re_dst = pcre_compile(dst, 0, &error, &erroffset, NULL);
99   xbt_assert(ruleroute->re_src,
100               "PCRE compilation failed at offset %d (\"%s\"): %s\n",
101               erroffset, dst, error);
102
103   ruleroute->re_str_link = route->link_list;
104   route->link_list = NULL; // Don't free it twice in each container
105
106   xbt_dynar_push(routing->list_route, &ruleroute);
107 }
108
109 static void model_rulebased_parse_ASroute(AS_t rc,
110                                         const char *src, const char *dst,
111                                         route_t route)
112 {
113   AS_rulebased_t routing = (AS_rulebased_t) rc;
114   rule_route_extended_t ruleroute_e = xbt_new0(s_rule_route_extended_t, 1);
115   const char *error;
116   int erroffset;
117
118   if(!strcmp(rc->model_desc->name,"Vivaldi")){
119           if(!xbt_dynar_is_empty(route->link_list))
120                   xbt_die("You can't have link_ctn with Model Vivaldi.");
121   }
122
123   ruleroute_e->generic_rule_route.re_src =
124       pcre_compile(src, 0, &error, &erroffset, NULL);
125   xbt_assert(ruleroute_e->generic_rule_route.re_src,
126               "PCRE compilation failed at offset %d (\"%s\"): %s\n",
127               erroffset, src, error);
128   ruleroute_e->generic_rule_route.re_dst =
129       pcre_compile(dst, 0, &error, &erroffset, NULL);
130   xbt_assert(ruleroute_e->generic_rule_route.re_src,
131               "PCRE compilation failed at offset %d (\"%s\"): %s\n",
132               erroffset, dst, error);
133   ruleroute_e->generic_rule_route.re_str_link =
134       route->link_list;
135   ruleroute_e->re_src_gateway = route->src_gateway;
136   ruleroute_e->re_dst_gateway = route->dst_gateway;
137   xbt_dynar_push(routing->list_ASroute, &ruleroute_e);
138
139   /* make sure that they don't get freed */
140   route->link_list = NULL;
141   route->src_gateway = route->dst_gateway = NULL;
142 }
143
144 static void model_rulebased_parse_bypassroute(AS_t rc,
145                                             const char *src,
146                                             const char *dst,
147                                             route_t e_route)
148 {
149   xbt_die("bypass routing not supported for Route-Based model");
150 }
151
152 #define BUFFER_SIZE 4096        /* result buffer size */
153 #define OVECCOUNT 30            /* should be a multiple of 3 */
154
155 static char *remplace(char *value, const char **src_list, int src_size,
156                       const char **dst_list, int dst_size)
157 {
158   char result[BUFFER_SIZE];
159   int i_res = 0;
160   int i = 0;
161
162   while (value[i]) {
163     if (value[i] == '$') {
164       i++;                      /* skip the '$' */
165       if (value[i] < '0' || value[i] > '9')
166         xbt_die("bad string parameter, no number indication, at offset: "
167                 "%d (\"%s\")", i, value);
168
169       /* solve the number */
170       int number = value[i++] - '0';
171       while (value[i] >= '0' && value[i] <= '9')
172         number = 10 * number + (value[i++] - '0');
173
174       /* solve the indication */
175       const char **param_list;
176       _XBT_GNUC_UNUSED int param_size;
177       if (value[i] == 's' && value[i + 1] == 'r' && value[i + 2] == 'c') {
178         param_list = src_list;
179         param_size = src_size;
180       } else if (value[i] == 'd' && value[i + 1] == 's'
181                  && value[i + 2] == 't') {
182         param_list = dst_list;
183         param_size = dst_size;
184       } else {
185         xbt_die("bad string parameter, support only \"src\" and \"dst\", "
186                 "at offset: %d (\"%s\")", i, value);
187       }
188       i += 3;
189
190       xbt_assert(number < param_size,
191                  "bad string parameter, not enough length param_size, "
192                  "at offset: %d (\"%s\") %d %d", i, value, param_size, number);
193
194       const char *param = param_list[number];
195       int j = 0;
196       while (param[j] && i_res < BUFFER_SIZE)
197         result[i_res++] = param[j++];
198     } else {
199       result[i_res++] = value[i++]; /* next char */
200     }
201     if (i_res >= BUFFER_SIZE)
202       xbt_die("solving string \"%s\", small buffer size (%d)",
203               value, BUFFER_SIZE);
204   }
205   result[i_res++] = '\0';
206   char *res = xbt_malloc(i_res);
207   return memcpy(res, result, i_res);
208 }
209
210 static void rulebased_get_route_and_latency(AS_t rc,
211                                 const char *src, const char *dst,
212                                 route_t res,double*lat);
213 static xbt_dynar_t rulebased_get_onelink_routes(AS_t rc)
214 {
215   xbt_dynar_t ret = xbt_dynar_new (sizeof(onelink_t), xbt_free);
216
217   //We have already bypass cluster routes with network NS3
218   if(!strcmp(surf_network_model->name,"network NS3"))
219         return ret;
220
221   AS_rulebased_t routing = (AS_rulebased_t)rc;
222
223   xbt_dict_cursor_t c1 = NULL;
224   char *k1, *d1;
225
226   //find router
227   char *router = NULL;
228   xbt_dict_foreach(routing->dict_processing_units, c1, k1, d1) {
229     if (routing_get_network_element_type(k1) == SURF_NETWORK_ELEMENT_ROUTER){
230       router = k1;
231       break;
232     }
233   }
234
235   if (!router)
236     xbt_die ("rulebased_get_onelink_routes works only if the AS is a cluster, sorry.");
237
238   xbt_dict_foreach(routing->dict_processing_units, c1, k1, d1) {
239     route_t route = xbt_new0(s_route_t,1);
240     route->link_list = xbt_dynar_new(global_routing->size_of_link,NULL);
241     rulebased_get_route_and_latency (rc, router, k1, route,NULL);
242
243     int number_of_links = xbt_dynar_length(route->link_list);
244
245     if(number_of_links == 1) {
246                 //loopback
247     }
248     else{
249                 if (number_of_links != 2) {
250                   xbt_die ("rulebased_get_onelink_routes works only if the AS is a cluster, sorry.");
251                 }
252
253                 void *link_ptr;
254                 xbt_dynar_get_cpy (route->link_list, 1, &link_ptr);
255                 onelink_t onelink = xbt_new0 (s_onelink_t, 1);
256                 onelink->src = xbt_strdup (k1);
257                 onelink->dst = xbt_strdup (router);
258                 onelink->link_ptr = link_ptr;
259                 xbt_dynar_push (ret, &onelink);
260     }
261   }
262   return ret;
263 }
264
265 /* Business methods */
266 static void rulebased_get_route_and_latency(AS_t rc,
267                                 const char *src, const char *dst,
268                                 route_t route, double *lat)
269 {
270   xbt_assert(rc && src
271               && dst,
272               "Invalid params for \"get_route\" function at AS \"%s\"",
273               rc->name);
274
275   /* set utils vars */
276   AS_rulebased_t routing = (AS_rulebased_t) rc;
277
278   int are_processing_units=0;
279   xbt_dynar_t rule_list;
280   if (xbt_dict_get_or_null(routing->dict_processing_units, src)
281       && xbt_dict_get_or_null(routing->dict_processing_units, dst)) {
282     are_processing_units = 1;
283     rule_list = routing->list_route;
284   } else if (xbt_dict_get_or_null(routing->dict_autonomous_systems, src)
285              && xbt_dict_get_or_null(routing->dict_autonomous_systems,
286                                      dst)) {
287     are_processing_units = 0;
288     rule_list = routing->list_ASroute;
289   } else
290     THROWF(arg_error,0,"No route from '%s' to '%s'",src,dst);
291
292   int rc_src = -1;
293   int rc_dst = -1;
294   int src_length = (int) strlen(src);
295   int dst_length = (int) strlen(dst);
296
297   rule_route_t ruleroute;
298   unsigned int cpt;
299   int ovector_src[OVECCOUNT];
300   int ovector_dst[OVECCOUNT];
301   const char **list_src = NULL;
302   const char **list_dst = NULL;
303   _XBT_GNUC_UNUSED int res;
304   xbt_dynar_foreach(rule_list, cpt, ruleroute) {
305     rc_src =
306         pcre_exec(ruleroute->re_src, NULL, src, src_length, 0, 0,
307                   ovector_src, OVECCOUNT);
308     if (rc_src >= 0) {
309       rc_dst =
310           pcre_exec(ruleroute->re_dst, NULL, dst, dst_length, 0, 0,
311                     ovector_dst, OVECCOUNT);
312       if (rc_dst >= 0) {
313         res = pcre_get_substring_list(src, ovector_src, rc_src, &list_src);
314         xbt_assert(!res, "error solving substring list for src \"%s\"", src);
315         res = pcre_get_substring_list(dst, ovector_dst, rc_dst, &list_dst);
316         xbt_assert(!res, "error solving substring list for src \"%s\"", dst);
317         char *link_name;
318         xbt_dynar_foreach(ruleroute->re_str_link, cpt, link_name) {
319           char *new_link_name =
320               remplace(link_name, list_src, rc_src, list_dst, rc_dst);
321           void *link =
322                           xbt_lib_get_or_null(link_lib, new_link_name, SURF_LINK_LEVEL);
323           if (link) {
324             xbt_dynar_push(route->link_list, &link);
325             if (lat)
326               *lat += surf_network_model->extension.network.get_link_latency(link);
327           } else
328             THROWF(mismatch_error, 0, "Link %s not found", new_link_name);
329           xbt_free(new_link_name);
330         }
331       }
332     }
333     if (rc_src >= 0 && rc_dst >= 0)
334       break;
335   }
336
337   if (rc_src >= 0 && rc_dst >= 0) {
338     /* matched src and dest, nothing more to do (?) */
339   } else if (!strcmp(src, dst) && are_processing_units) {
340     xbt_dynar_push(route->link_list, &(global_routing->loopback));
341     if (lat)
342       *lat += surf_network_model->extension.network.get_link_latency(global_routing->loopback);
343   } else {
344     THROWF(arg_error,0,"No route from '%s' to '%s'??",src,dst);
345     //xbt_dynar_reset(route->link_list);
346   }
347
348   if (!are_processing_units && !xbt_dynar_is_empty(route->link_list)) {
349     rule_route_extended_t ruleroute_extended =
350         (rule_route_extended_t) ruleroute;
351     route->src_gateway =
352         remplace(ruleroute_extended->re_src_gateway, list_src, rc_src,
353                  list_dst, rc_dst);
354     route->dst_gateway =
355         remplace(ruleroute_extended->re_dst_gateway, list_src, rc_src,
356                  list_dst, rc_dst);
357   }
358
359   if (list_src)
360     pcre_free_substring_list(list_src);
361   if (list_dst)
362     pcre_free_substring_list(list_dst);
363 }
364
365 static route_t rulebased_get_bypass_route(AS_t rc, const char *src, const char *dst) {
366   return NULL;
367 }
368
369 static void rulebased_finalize(AS_t rc)
370 {
371   AS_rulebased_t routing =
372       (AS_rulebased_t) rc;
373   if (routing) {
374     xbt_dict_free(&routing->dict_processing_units);
375     xbt_dict_free(&routing->dict_autonomous_systems);
376     xbt_dynar_free(&routing->list_route);
377     xbt_dynar_free(&routing->list_ASroute);
378
379     model_generic_finalize(rc);
380   }
381 }
382
383 /* Creation routing model functions */
384 AS_t model_rulebased_create(void) {
385
386   AS_rulebased_t new_component = (AS_rulebased_t)
387       model_generic_create_sized(sizeof(s_AS_rulebased_t));
388
389   new_component->generic_routing.parse_PU = model_rulebased_parse_PU;
390   new_component->generic_routing.parse_AS = model_rulebased_parse_AS;
391   new_component->generic_routing.parse_route = model_rulebased_parse_route;
392   new_component->generic_routing.parse_ASroute = model_rulebased_parse_ASroute;
393   new_component->generic_routing.parse_bypassroute = model_rulebased_parse_bypassroute;
394   new_component->generic_routing.get_onelink_routes = rulebased_get_onelink_routes;
395   new_component->generic_routing.get_route_and_latency = rulebased_get_route_and_latency;
396   new_component->generic_routing.get_bypass_route = rulebased_get_bypass_route;
397   new_component->generic_routing.finalize = rulebased_finalize;
398   /* initialization of internal structures */
399   new_component->dict_processing_units = xbt_dict_new_homogeneous(NULL);
400   new_component->dict_autonomous_systems = xbt_dict_new_homogeneous(NULL);
401   new_component->list_route = xbt_dynar_new(sizeof(rule_route_t), &rule_route_free);
402   new_component->list_ASroute =
403       xbt_dynar_new(sizeof(rule_route_extended_t),
404                     &rule_route_extended_free);
405
406   return (AS_t) new_component;
407 }