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 * Library for using multiple links from a single class
34 *
35 * $Id: link_multi.c,v 1.8 2005-09-25 06:08:45 girod Exp $
36 */
37
38 char link_multi_cvsid[] = "$Id: link_multi.c,v 1.8 2005-09-25 06:08:45 girod Exp $";
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <time.h>
46
47 #include "liblink_i.h"
48 #include "link_multi.h"
49 #include "neighbor.h"
50 #include "libdev/directory_client.h"
51
52 struct _lu_multi_link {
53 QUEUE_ELEMENT_DECL(_,struct _lu_multi_link);
54
55 /* link listener state */
56 char *link_name;
57 int index;
58 lu_context_t *lu;
59
60 /* user data */
61 void *data;
62
63 /* neighbor listener state */
64 status_client_context_t *neighbors;
65 neighbor_t *curr_list;
66
67 lu_multi_context_t *parent;
68 };
69
70 struct _lu_multi_context {
71 lu_multi_opts_t opts;
72 dir_event_ctx_t *class_dir;
73 int warned;
74 QUEUE_DECL(links,struct _lu_multi_link);
75 struct _lu_multi_context **ref;
76 };
77
78
79 QUEUE_INLINE_INSTANTIATIONS(lum_links,_,links,lu_multi_link_t,lu_multi_context_t);
80 QUEUE_FUNCTION_INSTANTIATIONS(lum_links,_,links,lu_multi_link_t,lu_multi_context_t);
81
82
83 lu_multi_link_t *lu_multi_links_top(lu_multi_context_t *lu)
84 {
85 return lum_links_top(lu);
86 }
87
88
89 lu_multi_link_t *lu_multi_links_next(lu_multi_link_t *ptr)
90 {
91 return lum_links_next(ptr);
92 }
93
94
95 int lu_multi_links_qlen(lu_multi_context_t *lu)
96 {
97 return lum_links_qlen(lu);
98 }
99
100
101 lu_context_t *lu_multi_link_get_lu(lu_multi_link_t *l)
102 {
103 if (l) return l->lu;
104 return NULL;
105 }
106
107
108 void *lu_multi_link_get_data(lu_multi_link_t *l)
109 {
110 if (l) return l->data;
111 return NULL;
112 }
113
114
115 void lu_multi_link_set_data(lu_multi_link_t *l, void *data)
116 {
117 if (l) l->data = data;
118 }
119
120
121 int lu_multi_link_get_index(lu_multi_link_t *l)
122 {
123 if (l) return l->index;
124 return -1;
125 }
126
127
128 char *lu_multi_link_get_name(lu_multi_link_t *l)
129 {
130 if (l) return l->link_name;
131 return NULL;
132 }
133
134
135 lu_multi_context_t *lu_multi_link_get_parent(lu_multi_link_t *l)
136 {
137 if (l) return l->parent;
138 return NULL;
139 }
140
141
142 void *lu_multi_get_data(lu_multi_context_t *lm)
143 {
144 if (lm) return lm->opts.lu_opts.opts.data;
145 return NULL;
146 }
147
148
149
150 lu_multi_link_t *lu_multi_index_link(lu_multi_context_t *lu, int index)
151 {
152 lu_multi_link_t *l;
153 for (l=lum_links_top(lu); l; l=lum_links_next(l)) {
154 if (l->index == index) return l;
155 }
156 return NULL;
157 }
158
159
160 lu_multi_link_t *lu_multi_lookup_link(lu_multi_context_t *lu, const char *name)
161 {
162 lu_multi_link_t *l;
163 for (l=lum_links_top(lu); l; l=lum_links_next(l)) {
164 if (strcmp(name, l->link_name) == 0) return l;
165 }
166 return NULL;
167 }
168
169
170 static
171 int lum_receive(lu_context_t *lu, link_pkt_t *pkt, ssize_t data_len)
172 {
173 lu_multi_link_t *l = (lu_multi_link_t *)lu_data(lu);
174 pkt->link_index = l->index;
175
176 if (l->parent->opts.receive) {
177 int status = l->parent->opts.receive(l, pkt, data_len);
178 if (status == EVENT_DONE) {
179 lu_multi_destroy(l->parent);
180 return EVENT_DONE;
181 }
182 }
183 else
184 free(pkt);
185
186 return EVENT_RENEW;
187 }
188
189
190 static
191 int lum_status(lu_context_t *lu)
192 {
193 lu_multi_link_t *l = (lu_multi_link_t *)lu_data(lu);
194
195 if (l->parent->opts.status_notify)
196 l->parent->opts.status_notify(l->parent, l);
197
198 return EVENT_RENEW;
199 }
200
201
202 static
203 int lum_neighbor_list(neighbor_t *nb_list, int count, void *data)
204 {
205 lu_multi_link_t *l = (lu_multi_link_t *)data;
206 if (l->curr_list) free(l->curr_list);
207 l->curr_list = nb_list;
208 if (l->parent->opts.neighbor_change)
209 l->parent->opts.neighbor_change(l->parent, l);
210 return EVENT_RENEW;
211 }
212
213
214 int lu_multi_if_to_node(lu_multi_context_t *lu, if_id_t if_id, node_id_t *node_id)
215 {
216 lu_multi_link_t *l;
217 int filled = 0;
218 for (l=lum_links_top(lu); l; l=lum_links_next(l)) {
219 if (l->curr_list) {
220 int i;
221 for (i=0; l->curr_list[i].node_id; i++)
222 if (l->curr_list[i].if_id == if_id) {
223 if (node_id) *node_id = l->curr_list[i].node_id;
224 if (l->curr_list[i].state == ACTIVE)
225 return 0;
226 filled = 1;
227 }
228 }
229 }
230 if (filled) return 1;
231 return -1;
232 }
233
234
235 int lu_multi_node_to_if(lu_multi_context_t *lu, node_id_t node_id, if_id_t *if_id, int *index)
236 {
237 lu_multi_link_t *l;
238 int filled = 0;
239 for (l=lum_links_top(lu); l; l=lum_links_next(l)) {
240 if (l->curr_list) {
241 int i;
242 for (i=0; l->curr_list[i].node_id; i++)
243 if (l->curr_list[i].node_id == node_id) {
244 if (index) *index = l->index;
245 if (if_id) *if_id = l->curr_list[i].if_id;
246 if (l->curr_list[i].state == ACTIVE)
247 return 0;
248 filled = 1;
249 }
250 }
251 }
252 if (filled) return 1;
253 return -1;
254 }
255
256
257 int lu_multi_link_get_conn(lu_multi_link_t *l, if_id_t if_id)
258 {
259 if (l->curr_list) {
260 int i;
261 for (i=0; l->curr_list[i].node_id; i++)
262 if (l->curr_list[i].if_id == if_id) {
263 return l->curr_list[i].conn_from;
264 }
265 }
266 return -1;
267 }
268
269
270 static
271 lu_multi_link_t *lu_multi_open_link(lu_multi_context_t *lu,
272 const char *link_name, int index,
273 const char *neighbors_name)
274 {
275 lu_multi_link_t *l = g_new0(lu_multi_link_t,1);
276 lu_opts_t opts = lu->opts.lu_opts;
277
278 l->link_name = strdup(link_name ? link_name : neighbors_name);
279 l->index = index;
280 l->parent = lu;
281 l->data = opts.opts.data;
282
283 if (link_name) {
284 opts.opts.name = l->link_name;
285 opts.receive = lum_receive;
286 opts.status_notify = lum_status;
287 opts.opts.data = l;
288
289 if (lu_open(&opts, &(l->lu)) < 0) {
290 elog(LOG_WARNING, "Unable to open link %s", l->link_name);
291 free(l);
292 return NULL;
293 }
294 elog(LOG_NOTICE, "Opened link %s, index %d, filter %d",
295 l->link_name, index, opts.opts.pkt_type);
296 }
297
298 if (link_name || neighbors_name) {
299 /* connect to neighbors service */
300 neighbor_opts_t n_opts = {
301 link_name: neighbors_name ? (char*)neighbors_name : l->link_name,
302 new_list: lum_neighbor_list,
303 data: l,
304 no_init_crashproof:1
305 };
306
307 if (g_neighbors(&n_opts, &(l->neighbors)) < 0)
308 elog(LOG_WARNING, "Unable to connect to neighbors service on link %s",
309 n_opts.link_name);
310 else
311 elog(LOG_NOTICE, "Opened neighbors %s, index %d", n_opts.link_name, index);
312 }
313
314 lum_links_push(lu, l);
315 return l;
316 }
317
318
319 static
320 int lum_dir_update(dir_event_ctx_t *dir)
321 {
322 lu_multi_context_t *lu = remote_dir_event_data(dir);
323
324 /* iterate thru the directory */
325 for (remote_dir_event_top(dir);
326 remote_dir_event_valid(dir);
327 remote_dir_event_next(dir)) {
328
329 int num;
330 char *link = remote_dir_event_get_curr(dir, &num);
331
332 /* look it up */
333 lu_multi_link_t *lu_client = lu_multi_index_link(lu, num);
334
335 /* missing? create a new client */
336 if (lu_client == NULL) {
337 lu_multi_link_t *l = lu_multi_open_link(lu, link, num, link);
338 if (l && lu->opts.new_link)
339 lu->opts.new_link(lu, l);
340 }
341 }
342
343 return EVENT_RENEW;
344 }
345
346
347 int lu_multi_get_if_id(lu_multi_context_t *lum, int interface, if_id_t *iid)
348 {
349 lu_multi_link_t *lu = lu_multi_index_link(lum, interface);
350 if (lu == NULL) elog(LOG_NOTICE, "Can't find interface index %d", interface);
351 else {
352 lu_context_t *lu2 = lu_multi_link_get_lu(lu);
353 if (lu2) return lu_get_if_id(lu2, iid);
354 elog(LOG_NOTICE, "Can't find interface index %d --2", interface);
355 }
356 return -1;
357 }
358
359
360
361 int lu_multi_send(lu_multi_context_t *lm, int interface, link_pkt_t *pkt, ssize_t data_len)
362 {
363 lu_multi_link_t *lu = lu_multi_index_link(lm, interface);
364 if (lu)
365 return lu_send(lu_multi_link_get_lu(lu), pkt, data_len);
366 errno = ENODEV;
367 return -1;
368 }
369
370
371 void lu_multi_destroy(lu_multi_context_t *lu)
372 {
373 if (lu) {
374 lu_multi_link_t *l;
375
376 if (lu->ref) *(lu->ref) = NULL;
377
378 while ((l=lum_links_pop(lu))) {
379 lu_destroy(l->lu);
380 free(l->link_name);
381 free(l);
382 }
383
384 remote_dir_event_destroy(lu->class_dir);
385 free(lu->opts.if_class);
386
387 free(lu);
388 }
389 }
390
391
392 int lum_warning(void *data, int interval, g_event_t *ev)
393 {
394 lu_multi_context_t *lum = (lu_multi_context_t *)data;
395 if (lum_links_qlen(lum) > 0) {
396 if (lum->warned)
397 elog(LOG_WARNING, "Got a link.. link_multi OK");
398 return TIMER_DONE;
399 }
400
401 if (lum->warned < 3)
402 elog(LOG_WARNING, "%sNO LINKS yet in class %s.. did you create any?",
403 lum->warned > 0 ? "Still " : "",
404 lum->opts.if_class);
405 lum->warned++;
406
407 return TIMER_RENEW;
408 }
409
410
411 int lu_open_multi(lu_multi_opts_t *opts, lu_multi_context_t **ref)
412 {
413 lu_multi_context_t *lu = g_new0(lu_multi_context_t,1);
414 char buf[128];
415 char *dir_name;
416
417 sprintf(buf, "/dev/link/classes/%s", opts->if_class);
418 dir_name = sim_path(buf);
419
420 lu->opts = *opts;
421 lu->opts.lu_opts.opts.name = NULL;
422 lu->opts.lu_opts.opts.if_class = NULL;
423 lu->opts.if_class = strdup(lu->opts.if_class);
424 lu->opts.neighbors_list =
425 lu->opts.neighbors_list ? strdup(lu->opts.neighbors_list) : NULL;
426
427 if (lu->opts.receive == NULL)
428 elog(LOG_WARNING, "no packet receive handler specified");
429
430 /* set ref now because callbacks may be invoked */
431 if (ref) {
432 if (*ref) {
433 elog(LOG_WARNING, "Destroying reference");
434 lu_multi_destroy(*ref);
435 }
436 *ref = lu;
437 }
438
439 /* register for directory info */
440 if (remote_dir_event_new(dir_name, lum_dir_update, lu, &(lu->class_dir)) < 0) {
441 elog(LOG_WARNING, "Unable to open %s class direcotory", dir_name);
442 if (ref) *ref = NULL;
443 free(lu);
444 return -1;
445 }
446
447 /* if neighbors devs specified process them now */
448 /* $$$ parse csv */
449 if (lu->opts.neighbors_list) {
450 lu_multi_open_link(lu, NULL, -1, lu->opts.neighbors_list);
451 }
452
453 /* set timer to emit warning message if you forgot to have anything in your class.. */
454 if (!lu->opts.withhold_warning)
455 g_timer_add(10000, lum_warning, lu, NULL, NULL);
456
457 return 0;
458 }
459
460
461
462
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.