~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
cvs/emstar/routing/geo-linkstate/route_table.c


  1 /*
  2  *
  3  * Copyright (c) 2003 The Regents of the University of California.  All 
  4  * rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  *
 10  * - Redistributions of source code must retain the above copyright
 11  *   notice, this list of conditions and the following disclaimer.
 12  *
 13  * - Neither the name of the University nor the names of its
 14  *   contributors may be used to endorse or promote products derived
 15  *   from this software without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 20  * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  *
 29  */
 30  
 31 
 32 
 33 #include "common.h"
 34 #include "dijkstra.h"
 35 #include "gls_i.h"
 36 #include "hash.h"
 37 
 38 #define MY_LOG_LEVEL LOG_DEBUG(4)
 39 
 40 struct dijkstra_args
 41 {
 42   /* options governing operations of the node on which this algorithm is
 43    * running */
 44   struct nodeconf *cfg;
 45   /* this parameter is used by callbacks to keep track of the node that is
 46    * being currently processed */
 47   ulong curId;
 48   /* adjacency matrix */
 49   ulong **adj;
 50   /* when creating an adjacency matrix, we can't use "real" node ids, since
 51    * they may be non-consecutive. Hence, we map node ids to consecutive
 52    * numbers (which we call dijkstra ids). This table holds the mappings */
 53   GHashTable *nodeToDijkstra;
 54   /* array mapping dijkstra ids to "real" ids */
 55   ulong *dijkstraToNode;
 56   /* need to make use of the global configuration table while figuring out
 57    * edge weights, etc */
 58   GHashTable *nodeTable;
 59 };
 60 
 61 void
 62 destroy_routedev_nodeinfo(gpointer data)
 63 {
 64   assert(data);
 65   g_free(data);
 66 }
 67 
 68 /* TODO: explanation for the function */
 69 static void
 70 map_dijkstra(gpointer key, gpointer value, gpointer user_data)
 71 {
 72   ulong **dijkstra_to_node_element = (ulong **)user_data;
 73 
 74   assert(dijkstra_to_node_element);
 75   assert(* dijkstra_to_node_element);
 76   assert(value);
 77   assert(key);
 78 
 79   elog (MY_LOG_LEVEL, "mapping key %lu",* (ulong *)key);
 80 
 81   /* before calling the g_hash_table_foreach(), we set the (*
 82    * dijkstra_to_node_element) to point to the first element of the
 83    * dijkstra_to_node array, and then keep moving the pointer while walking
 84    * the table */
 85   (** dijkstra_to_node_element) = * (ulong *)key;
 86   /* advance the pointer to point to the next element */
 87   (* dijkstra_to_node_element) ++;
 88 }
 89 
 90 /* x - # of elts in the row
 91  * y - # of rows */
 92 ulong  **
 93 allocate_2d_array(int x, int y)
 94 {
 95   ulong **a;
 96   int i;
 97 
 98   assert((x > 0) && (y > 0));
 99 
100   /* allocate array of pointers to rows */
101   a = g_malloc(y * sizeof(ulong *));
102   /* allocate contiguous array to store the 2d array */
103   a[0] = g_malloc(x * y * sizeof(ulong  *));
104   /* adjust pointers in the row-pointer array to point to rows in 2d array
105    * (start with 1, as #0 is already set by virtue of g_malloc) */
106   for (i = 1; i < y; i++)
107     {
108       a[i] = a[0] + x * i;
109     }
110 
111   return a;
112 }
113 
114 /* TODO: allocate/destroy functions should probably be elsewhere */
115 void
116 destroy_2d_array(ulong **a)
117 {
118   assert(a && (*a));
119   g_free(a[0]); /* free contiguous space        */
120   g_free(a);            /* free the array of rows       */
121 }
122 
123 /* function to compute weights (distances) between the two nodes 'n1' and 'n2',
124  * given the information available from configuration structure 'cfg' */
125 ulong 
126 compute_weight(GHashTable *global, ulong n1, ulong n2)
127 {
128   struct nodeconf *cfgOne; 
129   struct nodeconf *cfgTwo; 
130   unsigned int dist;
131   unsigned int dist_x;
132   unsigned int dist_y;
133 
134   assert(global);
135 
136   cfgOne        = (struct nodeconf *)g_hash_table_lookup(global, &n1);
137   assert(cfgOne);
138 
139   cfgTwo = (struct nodeconf *)g_hash_table_lookup(global, &n2);
140   assert(cfgTwo);
141         
142   /* 
143    * if weight of the link between these two nodes was not given to us (we
144    * would not be in this function, if it was), compute this weight as a basic
145    * cartesian distance
146    */
147 
148   /* take care to make sure our unsigned integers do not wrap */
149   if (cfgOne->geo.x > cfgTwo->geo.x)
150     {
151       dist_x = cfgOne->geo.x - cfgTwo->geo.x;
152     }
153   else
154     {
155       dist_x = cfgTwo->geo.x - cfgOne->geo.x;
156     }
157 
158   if (cfgOne->geo.y > cfgTwo->geo.y)
159     {
160       dist_y = cfgOne->geo.y - cfgTwo->geo.y;
161     }
162   else
163     {
164       dist_y = cfgTwo->geo.y - cfgOne->geo.y;
165     }
166 
167   /* multiply by 100 since we want to keep weights as ulongs, but also
168    * dont want to lose too much precision. Only relative weights matter 
169    * anyway */
170   dist = ROUND_TO_ULONG(100 * sqrt(dist_x * dist_x + dist_y * dist_y));
171 
172   return dist;
173 }
174 
175 static void
176 add_edge(gpointer key, gpointer value, gpointer user_data)
177 {
178   struct dijkstra_args *args = (struct dijkstra_args *)user_data;
179   /* node configuration of the node we're interested in */
180   struct gls_neighbor *curNeighbor = (struct gls_neighbor *)value;
181   ulong weight;
182   ulong n1, n2;
183 
184   assert(args);
185   assert(curNeighbor);
186   assert(args->cfg);
187   assert(args->nodeTable);
188 
189   /*
190    * finally, add edge and weight information to proper arrays 
191    */
192 
193   /* lookup dijkstra id of node who's neighborlist we're walking */
194   n1 = (ulong) g_hash_table_lookup(args->nodeToDijkstra, 
195                                    (gpointer)args->curId);
196   /* lookup dijkstra id of the current neighbor */
197   n2 = (ulong) g_hash_table_lookup(args->nodeToDijkstra,
198                                    (gpointer)curNeighbor->id);
199 
200   elog (MY_LOG_LEVEL, "n1->n2 = %lu->%lu",n1,n2);
201 
202   /* we want to make sure this is not a problem: when using direct hashing
203    * (storing integers (longs in our case) in the space for pointers (value in
204    * the hash table)) we could legitimately store and find a value of ''. At
205    * the same time, g_hash_table_lookup() returns NULL if it can not find
206    * information we requested. So, to differentiate between the two cases, we
207    * do this extra reverse-check. It is totally unexpected for us to NOT find
208    * a dijkstra id of the node, hence the assert() */
209   assert(args->curId     == args->dijkstraToNode[n1]);
210 
211   /* it's possible to have the node on the neighborlist, but not have any
212    * information about the node */
213   if (curNeighbor->id != args->dijkstraToNode[n2])
214     {
215       /* yeah, we don't know anything about the neighbor( except the fact that
216        * it is present on the node's neighborlist..) */
217       return;
218     }
219 
220   /* are we supposed to compute weights of edges? */
221   if (args->cfg->use_cartesian_symmetric_weights)
222     {
223       /* compute weight of the edge between the node who's neighborlist we
224        * are currently processing (curNeighbor->id) and the current
225        * neighbor */
226       weight = compute_weight(args->nodeTable, args->curId, curNeighbor->id);
227 
228       /* fill the weight in the adjacency matrix (in this case, we assume
229        * symmetric links */
230       args->adj[n1][n2] = weight;
231       args->adj[n2][n1] = weight;
232 
233       elog (MY_LOG_LEVEL, "Symmetric: assigning weight args->adj[%lu][%lu]: %lu",
234             n1, n2, weight);
235 
236     }
237   else  /* don't assume symmetric links, and compute weights */
238     {
239 
240       /* in this case, we simply take the value of the weight from the
241        * neighbor structure. Notice, we're not setting adj[n2][n1], since
242        * links are not symmetric -- this will get set, if necessary, when
243        * walking the list of neighbors for n2 */
244       args->adj[n1][n2] = curNeighbor->weight;
245 
246       elog (MY_LOG_LEVEL, "Asymmetric: assigning weight args->adj[%lu][%lu]: %lu",
247             n1,n2, curNeighbor->weight);
248     }
249 }
250 
251 /* walks the neighborlist. Each callback will 'add an edge' to the adjacency
252  * matrix */
253 static void
254 walk_neighborlist(gpointer key, gpointer value, gpointer user_data)
255 {
256   struct dijkstra_args *args = (struct dijkstra_args *)user_data;
257   /* node configuration of the node we're interested in */
258   struct nodeconf *curNodeCfg = (struct nodeconf *)value;
259 
260   buf_t *bf = buf_new();
261 
262 
263   assert(args);
264   assert(curNodeCfg);
265 
266   elog (MY_LOG_LEVEL, "Walking NodeID: %d",curNodeCfg->id);
267   print_neighborlist(curNodeCfg,bf);
268   elog_g(MY_LOG_LEVEL, "%s",bf->buf);
269   buf_free(bf);
270 
271   /* set id of the node, who's neighborlist we're about to process */
272   args->curId = * (ulong *)key;
273   /* walk the neighborlist */
274   g_hash_table_foreach(curNodeCfg->neighbor_list, add_edge, (gpointer)args);
275 }
276 
277 /* TODO: needs a comment on why we're doing what we're doing with conversions,
278  * etc */
279 /* TODO: perhaps rename this function to 'rebuild_routing_table', as it will
280  * indicate that we actually destroy/reallocate it? */
281 void
282 compute_routing_table(struct routedev_info *tables, struct nodeconf *config)
283 {
284   /* table mapping dijkstra consecutive ids to node ids */
285   static ulong *dijkstra_to_node = NULL;
286   /* table mapping node ids to consecutive dijkstra ids */
287   GHashTable *nodeToDijkstra;   
288   /* temp counter(s) */
289   unsigned int i, j;
290   /* dijkstra id of the node we're running on (node from which we will seek
291    * out the paths */
292   ulong thisNode;
293   /* arguments needed for the dijkstra algorithm */
294   struct dijkstra_args args;
295   /* predecessor array: element p[j] is a predecessor of node j on the path
296    * from the node we're running on now */
297   static ulong *p = NULL;
298   static unsigned long int nodeid_table_size = 0;
299   struct routedev_nodeinfo *curNodePtr = NULL;
300   unsigned long int nextHop = 0;
301   unsigned long int cur = 0;
302 
303   /* definitions for printing out routing paths */
304   gboolean self = FALSE;
305   gboolean path_exists = FALSE;
306   GSList *path;
307   GSList *cur_path_elt;
308 
309 
310   ulong *dijkstra_to_node_element = NULL;
311 
312   assert(tables);
313   /* noteid table must've been created by the time this function is called */
314   assert(tables->nodeid);       
315   assert(config);
316         
317   elog (MY_LOG_LEVEL, "sizeof(tables->nodeid) = %d",g_hash_table_size(tables->nodeid));
318 
319   /* if number of nodes we're dealing with changed... */
320   if (nodeid_table_size != g_hash_table_size(tables->nodeid))
321     {
322       /* ... reallocate the dijkstra_to_node table */
323       nodeid_table_size = g_hash_table_size(tables->nodeid);
324       dijkstra_to_node = g_realloc(dijkstra_to_node,
325                                    sizeof(ulong) * nodeid_table_size);
326       /* ... reallocate predecessor array */
327       p = g_realloc(p, sizeof(ulong) * nodeid_table_size);
328     }
329 
330   dijkstra_to_node_element = dijkstra_to_node;
331   /* walk the nodeid table and for each nodeid we encounter, add an entry to
332    * the dijkstra_to_node table */
333   g_hash_table_foreach(tables->nodeid, map_dijkstra, 
334                        &dijkstra_to_node_element);
335 
336   /* now lets generate reverse mappings: nodeId -> dijkstraId */
337   nodeToDijkstra = g_hash_table_new(g_direct_hash, g_direct_equal);
338   assert(nodeToDijkstra);
339 
340   for (i = 0; i < nodeid_table_size; i ++)
341     {
342       g_hash_table_insert(nodeToDijkstra, 
343                           (gpointer)(dijkstra_to_node[i]), 
344                           (gpointer)i);
345     }
346 
347   elog (MY_LOG_LEVEL, "config->id:%d",config->id);
348 
349   thisNode = (ulong)g_hash_table_lookup(nodeToDijkstra, (gpointer)config->id);
350 
351   elog (MY_LOG_LEVEL, "config->id:%d ThisNode:%lu",config->id,thisNode);
352 
353   /* now we need to go create an adjacency matrix */
354   args.cfg                      = config;
355   args.nodeToDijkstra = nodeToDijkstra;
356   args.dijkstraToNode = dijkstra_to_node;
357   args.nodeTable                = tables->nodeid;       
358   args.adj                      = allocate_2d_array(nodeid_table_size, 
359                                                     nodeid_table_size);
360 
361   /* initialize the 2d adjacency matrix prior to use */
362   for (i = 0; i < nodeid_table_size; i++)
363     {
364       for (j = 0; j < nodeid_table_size; j++)
365         {
366           args.adj[i][j] = INFINITY;
367         }
368     }
369 
370   /* walk the node table, and for every configuration structure encountered
371    * there call the function, which will in turn walk the neighborlist and add
372    * proper edges to the dijkstra_args structure 'args' */
373   g_hash_table_foreach(tables->nodeid, walk_neighborlist, (gpointer)&args);
374 
375 
376   /* Save adjacency matrix for status device to print */
377   
378   if (tables->adjbuf != NULL)  buf_free(tables->adjbuf);
379   tables->adjbuf = buf_new();
380   //  buf = tables->adjbuf;
381 
382   /* print an adjacency table */
383   bufprintf(tables->adjbuf,"----------------------------------------\n");
384   bufprintf(tables->adjbuf,"ADJACENCY TABLE\n");
385   bufprintf(tables->adjbuf,"----------------------------------------\n");
386   bufprintf(tables->adjbuf,"      ");
387 
388   for (i = 0; i < nodeid_table_size; i++)
389     {
390       bufprintf(tables->adjbuf,"%03lu ", dijkstra_to_node[i]); 
391     }
392 
393   bufprintf(tables->adjbuf,"\n");
394 
395   for (i = 0; i < nodeid_table_size; i++)
396     {
397       bufprintf(tables->adjbuf,"%03lu : ", dijkstra_to_node[i]); 
398       for (j = 0; j < nodeid_table_size; j++)
399         {
400           if (INFINITY == args.adj[i][j])
401             bufprintf(tables->adjbuf,"xxx ");
402           else
403             bufprintf(tables->adjbuf,"%3lu ", args.adj[i][j]);
404         }
405 
406       bufprintf(tables->adjbuf,"\n");
407     }
408 
409   elog(MY_LOG_LEVEL,"%s",(tables->adjbuf)->buf);
410 /* End of Print Adjacency Matrix */
411 
412         /* initialize all predecessors to some sentinel value, which means "no
413          * route" */
414   for (i = 0; i < nodeid_table_size; i++)
415     {
416       p[i] = INFINITY;
417     }
418         
419   /* now the adjacency matrix is filled in, and we're ready to run dijkstra
420    * algorithm to compute the next hop information */
421   (void)dijkstra(args.adj, nodeid_table_size, thisNode, p);
422 
423   /* print node to dijkstra array */
424   for (i = 0; i < nodeid_table_size; i++)
425       elog (MY_LOG_LEVEL,"DijkId:%d   NodeId:%lu", i, dijkstra_to_node[i]);
426 
427   /* print predecessor array */
428   for (i = 0; i < nodeid_table_size; i++)
429     {
430       if (p[i] == INFINITY) 
431         elog (MY_LOG_LEVEL, "ThisNode:%lu p[%d] = INFINITY",dijkstra_to_node[thisNode],i);
432       else
433         elog (MY_LOG_LEVEL, "ThisNode:%lu p[%d] = %lu",dijkstra_to_node[thisNode],i,p[i]);
434     }
435   
436 
437   /* if there already was a routing table, this one may be quite different, so
438    * we remove all of the old entries */
439   if (tables->rtable)
440     {
441       /* individual tables will be deallocated using the hook we pass in when
442        * making a table (destroy_routedev_nodeinfo) */
443       g_hash_table_destroy(tables->rtable);
444     }
445 
446   /* ok, lets create our routing table. It will contain routedev_nodeinfo
447    * structures, which have their id as the first element, which means we can
448    * reuse the hash_u32 and hash_compare_u32. This table contains only
449    * information in terms of nodeids. nothing else. For mapping of nodeid to
450    * other node attributes/addresses refer to the tables->nodeid table */
451   if (! (tables->rtable = g_hash_table_new_full(hash_u32, 
452                                                 hash_compare_u32, 
453                                                 NULL /* key destroy */,
454                                                 destroy_routedev_nodeinfo)))
455     {
456       printf("Error allocating routing table!\n");
457       exit(1);
458     }
459 
460   /* Printing Paths */
461   if (tables->rtablebuf)  buf_free(tables->rtablebuf);
462   tables->rtablebuf = buf_new();
463 
464   bufprintf(tables->rtablebuf,"----------------------------------------\n");
465   bufprintf(tables->rtablebuf,"ROUTING PATHS\n");
466   bufprintf(tables->rtablebuf,"----------------------------------------\n");
467   /* End Printing Paths */
468 
469   /* trace back the path from node 'i' to the starting node, to get the
470    * "next hop" information from the node we're running dijkstra for, to
471    * all others */
472   for (i = 0; i < nodeid_table_size; i++)
473     {
474 
475   /* Printing Paths */
476       self = FALSE;
477       path_exists = FALSE;
478 
479       if (i == thisNode)
480         {
481           self = TRUE;
482         }
483   /* End Printing Paths */
484 
485       nextHop = INFINITY;
486       cur     = i;
487 
488   /* Printing Paths */
489       path = NULL;
490       bufprintf(tables->rtablebuf,"Route from %03lu to %03lu : ",
491              dijkstra_to_node[thisNode], dijkstra_to_node[i]);
492   /* End Printing Paths */
493 
494       /* we'll hit the loop break out condition when there is
495        * no path to the starting node -- this happens when we reach a node
496        * whos predecessor is the node itself. Well, this will also happen for
497        * the starting node, since it's always a predecessor of itself. We
498        * check for the latter after we break out */
499       for (cur = i, curNodePtr = NULL; p[cur] != cur; cur = p[cur])
500         {
501           /* when the predecessor node of the one we're looking at now is a
502            * 'thisNode', the node we're looking at now is the next hop (since
503            * we're looking backwards), so we stop. */
504           if (thisNode == p[cur])
505             {
506   /* Printing Paths */
507               path_exists = TRUE;
508   /* End Printing Paths */
509               nextHop = cur;
510               break;
511             }
512           else if (INFINITY == p[cur]) /* sentinel, meaning "no predecessor"*/
513             {
514   /* Printing Paths */
515               path_exists = FALSE;
516   /* End Printing Paths */
517               break;
518             }
519 
520   /* Printing Paths */
521           path = g_slist_prepend(path, (gpointer)dijkstra_to_node[p[cur]]);
522   /* End Printing Paths */
523         }
524 
525   /* Printing Paths */
526       if (TRUE == self)
527         {
528           bufprintf(tables->rtablebuf,"Self");
529         }
530       else if (FALSE == path_exists)
531         {
532           bufprintf(tables->rtablebuf,"No Path");
533         }
534       else
535         {
536           int k = 0;
537 
538           bufprintf(tables->rtablebuf,"%lu ", (unsigned long int)config->id); 
539 
540           /* go through the list and print the path */
541           for (cur_path_elt = path, k = 0; 
542                cur_path_elt; 
543                cur_path_elt = g_slist_next(cur_path_elt))
544             {
545               bufprintf(tables->rtablebuf,"-> %lu ", (unsigned long int)cur_path_elt->data);
546 
547               if (k < 10)
548                 {
549                   k++;
550                 }
551               else
552                 {
553                   bufprintf(tables->rtablebuf,"\n                 : ");
554                   k = 0;
555                 }
556             }
557                         
558           bufprintf(tables->rtablebuf,"-> %lu ", (unsigned long int)dijkstra_to_node[i]);
559         }
560 
561       bufprintf(tables->rtablebuf,"\n");
562 
563       /* ok, now that we've printed everything, free the list */
564       g_slist_free(path);
565       path = NULL;
566 
567       elog(MY_LOG_LEVEL,"%s",(tables->rtablebuf)->buf);
568   /* End Printing Paths */
569 
570       if (i != thisNode)  /* we dont enter routes to self into the table */
571         {
572           /* ...  but we do enter "no route" information. i.e. we dont check
573            * whether nextHop is INFINITY or not. Even if it is, we enter
574            * anyway */
575           curNodePtr = g_new0(struct routedev_nodeinfo, 1);
576 
577           curNodePtr->id = dijkstra_to_node[i];
578 
579           if (INFINITY == nextHop)
580             {
581               curNodePtr->next_hop = INFINITY;
582             }
583           else
584             {
585               curNodePtr->next_hop = dijkstra_to_node[nextHop];
586             }
587 
588           // add an item to the hash table
589           g_hash_table_insert(tables->rtable, &(curNodePtr->id), curNodePtr);
590         }
591 
592     } /* for */
593 
594   /* deallocate everything we've allocated */
595 
596   /* we only have to destroy the table, as we don't dynamically allocate it's
597    * elements - we use direct hashing */
598   g_hash_table_destroy(nodeToDijkstra);
599 
600   /* destroy adjacency table. The next time we're called, it may be completely
601    * different */
602   destroy_2d_array(args.adj);
603 }
604 
605 
606 static void
607 print_routedev_nodeinfo(gpointer key, gpointer value, gpointer user_data)
608 {
609         /* we dont care to print the 'key's, only the values */
610         struct routedev_nodeinfo *route = value;
611 
612         assert(route);
613         elog(MY_LOG_LEVEL, "Nexthop to %lu -> %lu",route->id,route->next_hop);
614 }
615 
616 
617 void
618 print_routing_table(GHashTable *rtable)
619 {
620         assert(rtable);
621         g_hash_table_foreach(rtable, print_routedev_nodeinfo, NULL);
622 }
623 
624 static int rtablestatus_printable(status_context_t *info, buf_t *buf)
625 {
626   struct routedev_info *tables = (struct routedev_info *)sd_data(info);
627 
628   if (!tables->rtablebuf)
629     bufprintf(buf, "No Routing Table");
630   else
631   bufcpy(buf,(tables->rtablebuf)->buf,(tables->rtablebuf)->len);
632   
633   return STATUS_MSG_COMPLETE;
634 }
635 
636 static int adjstatus_printable(status_context_t *info, buf_t *buf)
637 {
638   struct routedev_info *tables = (struct routedev_info *)sd_data(info);
639   
640   if (!tables->adjbuf)
641     bufprintf(buf, "No Adjacency List");
642   else
643     bufprintf(buf,"%s",(tables->adjbuf)->buf);
644   //    bufcpy(buf,(tables->adjbuf)->buf,(tables->adjbuf)->len);
645   
646   return STATUS_MSG_COMPLETE;
647 }
648 
649 void tables_status_init(struct routedev_info *tables)
650 {
651   /* Basic opts for our neighbor status device */
652   status_dev_opts_t rtable_status_opts = {
653     device: {
654       devname: sim_path("/dev/link/routing/gls_rtable"),
655       device_info: tables,
656     },
657     printable: rtablestatus_printable
658   };
659 
660   /* Basic opts for our neighbor status device */
661   status_dev_opts_t adj_status_opts = {
662     device: {
663       devname: sim_path("/dev/link/routing/gls_adjlist"),
664       device_info: tables,
665     },
666     printable: adjstatus_printable
667   };
668 
669   tables->rtablestatus = NULL;
670 
671   /* Now create the status device */
672   if (g_status_dev(&rtable_status_opts, &tables->rtablestatus) < 0) {
673     elog(LOG_CRIT, "can't create status device /dev/link/routing/gls_rtable");
674     exit(1);
675   }
676 
677   tables->adjstatus = NULL;
678 
679   /* Now create the status device */
680   if (g_status_dev(&adj_status_opts, &tables->adjstatus) < 0) {
681     elog(LOG_CRIT, "can't create status device /dev/link/routing/gls_adjlist");
682     //    elog(LOG_CRIT, "can't create status device %s: %m", adj_status_opts.device.devname);
683     exit(1);
684   }
685 }
686 
687 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.