]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babeld.c
Merge pull request #3540 from donaldsharp/staic
[mirror_frr.git] / babeld / babeld.c
1 /*
2 Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 #include <zebra.h>
24 #include "command.h"
25 #include "prefix.h"
26 #include "memory.h"
27 #include "table.h"
28 #include "distribute.h"
29 #include "prefix.h"
30 #include "filter.h"
31 #include "plist.h"
32 #include "lib_errors.h"
33
34 #include "babel_main.h"
35 #include "babeld.h"
36 #include "util.h"
37 #include "net.h"
38 #include "kernel.h"
39 #include "babel_interface.h"
40 #include "neighbour.h"
41 #include "route.h"
42 #include "message.h"
43 #include "resend.h"
44 #include "babel_filter.h"
45 #include "babel_zebra.h"
46 #include "babel_memory.h"
47 #include "babel_errors.h"
48
49 static int babel_init_routing_process(struct thread *thread);
50 static void babel_get_myid(void);
51 static void babel_initial_noise(void);
52 static int babel_read_protocol (struct thread *thread);
53 static int babel_main_loop(struct thread *thread);
54 static void babel_set_timer(struct timeval *timeout);
55 static void babel_fill_with_next_timeout(struct timeval *tv);
56 static void
57 babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist);
58
59 /* Informations relative to the babel running daemon. */
60 static struct babel *babel_routing_process = NULL;
61 static unsigned char *receive_buffer = NULL;
62 static int receive_buffer_size = 0;
63
64 /* timeouts */
65 struct timeval check_neighbours_timeout;
66 static time_t expiry_time;
67 static time_t source_expiry_time;
68
69 /* Babel node structure. */
70 static struct cmd_node cmd_babel_node =
71 {
72 .node = BABEL_NODE,
73 .prompt = "%s(config-router)# ",
74 .vtysh = 1,
75 };
76
77 /* print current babel configuration on vty */
78 static int
79 babel_config_write (struct vty *vty)
80 {
81 int lines = 0;
82 int afi;
83 int i;
84
85 /* list enabled debug modes */
86 lines += debug_babel_config_write (vty);
87
88 if (!babel_routing_process)
89 return lines;
90 vty_out (vty, "router babel\n");
91 if (diversity_kind != DIVERSITY_NONE)
92 {
93 vty_out (vty, " babel diversity\n");
94 lines++;
95 }
96 if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
97 {
98 vty_out (vty, " babel diversity-factor %d\n",diversity_factor);
99 lines++;
100 }
101 if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
102 {
103 vty_out (vty, " babel resend-delay %u\n", resend_delay);
104 lines++;
105 }
106 if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
107 {
108 vty_out (vty, " babel smoothing-half-life %u\n",
109 smoothing_half_life);
110 lines++;
111 }
112 /* list enabled interfaces */
113 lines = 1 + babel_enable_if_config_write (vty);
114 /* list redistributed protocols */
115 for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
116 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
117 if (i != zclient->redist_default &&
118 vrf_bitmap_check (zclient->redist[afi][i], VRF_DEFAULT)) {
119 vty_out (vty, " redistribute %s %s\n",
120 (afi == AFI_IP) ? "ipv4" : "ipv6",
121 zebra_route_string(i));
122 lines++;
123 }
124 }
125 }
126
127 lines += config_write_distribute (vty, babel_routing_process->distribute_ctx);
128
129 return lines;
130 }
131
132
133 static int
134 babel_create_routing_process (void)
135 {
136 assert (babel_routing_process == NULL);
137
138 /* Allocaste Babel instance. */
139 babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel));
140
141 /* Initialize timeouts */
142 gettime(&babel_now);
143 expiry_time = babel_now.tv_sec + roughly(30);
144 source_expiry_time = babel_now.tv_sec + roughly(300);
145
146 /* Make socket for Babel protocol. */
147 protocol_socket = babel_socket(protocol_port);
148 if (protocol_socket < 0) {
149 flog_err_sys(EC_LIB_SOCKET, "Couldn't create link local socket: %s",
150 safe_strerror(errno));
151 goto fail;
152 }
153
154 /* Threads. */
155 thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
156 /* wait a little: zebra will announce interfaces, addresses, routes... */
157 thread_add_timer_msec(master, babel_init_routing_process, NULL, 200L, &babel_routing_process->t_update);
158
159 /* Distribute list install. */
160 babel_routing_process->distribute_ctx = distribute_list_ctx_create (vrf_lookup_by_id(VRF_DEFAULT));
161 distribute_list_add_hook (babel_routing_process->distribute_ctx, babel_distribute_update);
162 distribute_list_delete_hook (babel_routing_process->distribute_ctx, babel_distribute_update);
163 return 0;
164 fail:
165 XFREE(MTYPE_BABEL, babel_routing_process);
166 babel_routing_process = NULL;
167 return -1;
168 }
169
170 /* thread reading entries form others babel daemons */
171 static int
172 babel_read_protocol (struct thread *thread)
173 {
174 int rc;
175 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
176 struct interface *ifp = NULL;
177 struct sockaddr_in6 sin6;
178
179 assert(babel_routing_process != NULL);
180 assert(protocol_socket >= 0);
181
182 rc = babel_recv(protocol_socket,
183 receive_buffer, receive_buffer_size,
184 (struct sockaddr*)&sin6, sizeof(sin6));
185 if(rc < 0) {
186 if(errno != EAGAIN && errno != EINTR) {
187 flog_err_sys(EC_LIB_SOCKET, "recv: %s", safe_strerror(errno));
188 }
189 } else {
190 FOR_ALL_INTERFACES(vrf, ifp) {
191 if(!if_up(ifp))
192 continue;
193 if(ifp->ifindex == (ifindex_t)sin6.sin6_scope_id) {
194 parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
195 receive_buffer, rc);
196 break;
197 }
198 }
199 }
200
201 /* re-add thread */
202 thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
203 return 0;
204 }
205
206 /* Zebra will give some information, especially about interfaces. This function
207 must be call with a litte timeout wich may give zebra the time to do his job,
208 making these inits have sense. */
209 static int
210 babel_init_routing_process(struct thread *thread)
211 {
212 myseqno = (random() & 0xFFFF);
213 babel_get_myid();
214 babel_load_state_file();
215 debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
216 babel_initial_noise();
217 babel_main_loop(thread);/* this function self-add to the t_update thread */
218 return 0;
219 }
220
221 /* fill "myid" with an unique id (only if myid != {0}). */
222 static void
223 babel_get_myid(void)
224 {
225 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
226 struct interface *ifp = NULL;
227 int rc;
228 int i;
229
230 /* if we already have an id (from state file), we return. */
231 if (memcmp(myid, zeroes, 8) != 0) {
232 return;
233 }
234
235 FOR_ALL_INTERFACES(vrf, ifp) {
236 /* ifp->ifindex is not necessarily valid at this point */
237 int ifindex = if_nametoindex(ifp->name);
238 if(ifindex > 0) {
239 unsigned char eui[8];
240 rc = if_eui64(ifindex, eui);
241 if(rc < 0)
242 continue;
243 memcpy(myid, eui, 8);
244 return;
245 }
246 }
247
248 /* We failed to get a global EUI64 from the interfaces we were given.
249 Let's try to find an interface with a MAC address. */
250 for(i = 1; i < 256; i++) {
251 char buf[IF_NAMESIZE], *ifname;
252 unsigned char eui[8];
253 ifname = if_indextoname(i, buf);
254 if(ifname == NULL)
255 continue;
256 rc = if_eui64(i, eui);
257 if(rc < 0)
258 continue;
259 memcpy(myid, eui, 8);
260 return;
261 }
262
263 flog_err(EC_BABEL_CONFIG,
264 "Warning: couldn't find router id -- using random value.");
265
266 rc = read_random_bytes(myid, 8);
267 if(rc < 0) {
268 flog_err(EC_BABEL_CONFIG, "read(random): %s (cannot assign an ID)",
269 safe_strerror(errno));
270 exit(1);
271 }
272 /* Clear group and global bits */
273 myid[0] &= ~3;
274 }
275
276 /* Make some noise so that others notice us, and send retractions in
277 case we were restarted recently */
278 static void
279 babel_initial_noise(void)
280 {
281 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
282 struct interface *ifp = NULL;
283
284 FOR_ALL_INTERFACES(vrf, ifp) {
285 if(!if_up(ifp))
286 continue;
287 /* Apply jitter before we send the first message. */
288 usleep(roughly(10000));
289 gettime(&babel_now);
290 send_hello(ifp);
291 send_wildcard_retraction(ifp);
292 }
293
294 FOR_ALL_INTERFACES(vrf, ifp) {
295 if(!if_up(ifp))
296 continue;
297 usleep(roughly(10000));
298 gettime(&babel_now);
299 send_hello(ifp);
300 send_wildcard_retraction(ifp);
301 send_self_update(ifp);
302 send_request(ifp, NULL, 0);
303 flushupdates(ifp);
304 flushbuf(ifp);
305 }
306 }
307
308 /* Delete all the added babel routes, make babeld only speak to zebra. */
309 static void
310 babel_clean_routing_process()
311 {
312 flush_all_routes();
313 babel_interface_close_all();
314
315 /* cancel threads */
316 if (babel_routing_process->t_read != NULL) {
317 thread_cancel(babel_routing_process->t_read);
318 }
319 if (babel_routing_process->t_update != NULL) {
320 thread_cancel(babel_routing_process->t_update);
321 }
322
323 distribute_list_delete(&babel_routing_process->distribute_ctx);
324 XFREE(MTYPE_BABEL, babel_routing_process);
325 babel_routing_process = NULL;
326 }
327
328 /* Function used with timeout. */
329 static int
330 babel_main_loop(struct thread *thread)
331 {
332 struct timeval tv;
333 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
334 struct interface *ifp = NULL;
335
336 while(1) {
337 gettime(&babel_now);
338
339 /* timeouts --------------------------------------------------------- */
340 /* get the next timeout */
341 babel_fill_with_next_timeout(&tv);
342 /* if there is no timeout, we must wait. */
343 if(timeval_compare(&tv, &babel_now) > 0) {
344 timeval_minus(&tv, &tv, &babel_now);
345 debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs",
346 (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000);
347 /* it happens often to have less than 1 ms, it's bad. */
348 timeval_add_msec(&tv, &tv, 300);
349 babel_set_timer(&tv);
350 return 0;
351 }
352
353 gettime(&babel_now);
354
355 /* update database -------------------------------------------------- */
356 if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
357 int msecs;
358 msecs = check_neighbours();
359 /* Multiply by 3/2 to allow neighbours to expire. */
360 msecs = MAX(3 * msecs / 2, 10);
361 schedule_neighbours_check(msecs, 1);
362 }
363
364 if(babel_now.tv_sec >= expiry_time) {
365 expire_routes();
366 expire_resend();
367 expiry_time = babel_now.tv_sec + roughly(30);
368 }
369
370 if(babel_now.tv_sec >= source_expiry_time) {
371 expire_sources();
372 source_expiry_time = babel_now.tv_sec + roughly(300);
373 }
374
375 FOR_ALL_INTERFACES(vrf, ifp) {
376 babel_interface_nfo *babel_ifp = NULL;
377 if(!if_up(ifp))
378 continue;
379 babel_ifp = babel_get_if_nfo(ifp);
380 if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
381 send_hello(ifp);
382 if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
383 send_update(ifp, 0, NULL, 0);
384 if(timeval_compare(&babel_now,
385 &babel_ifp->update_flush_timeout) >= 0)
386 flushupdates(ifp);
387 }
388
389 if(resend_time.tv_sec != 0) {
390 if(timeval_compare(&babel_now, &resend_time) >= 0)
391 do_resend();
392 }
393
394 if(unicast_flush_timeout.tv_sec != 0) {
395 if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
396 flush_unicast(1);
397 }
398
399 FOR_ALL_INTERFACES(vrf, ifp) {
400 babel_interface_nfo *babel_ifp = NULL;
401 if(!if_up(ifp))
402 continue;
403 babel_ifp = babel_get_if_nfo(ifp);
404 if(babel_ifp->flush_timeout.tv_sec != 0) {
405 if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
406 flushbuf(ifp);
407 }
408 }
409 }
410
411 assert(0); /* this line should never be reach */
412 }
413
414 static void
415 printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
416 {
417 static struct timeval curr_tv;
418 static char buffer[200];
419 static const char *curr_tag = NULL;
420
421 switch (cmd) {
422 case 0: /* reset timeval */
423 curr_tv = *tv;
424 if(ifname != NULL) {
425 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
426 curr_tag = buffer;
427 } else {
428 curr_tag = tag;
429 }
430 break;
431 case 1: /* take the min */
432 if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
433 break;
434 }
435 if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
436 tv->tv_usec < curr_tv.tv_usec)) {
437 curr_tv = *tv;
438 if(ifname != NULL) {
439 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
440 curr_tag = buffer;
441 } else {
442 curr_tag = tag;
443 }
444 }
445 break;
446 case 2: /* print message */
447 debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
448 break;
449 default:
450 break;
451 }
452 }
453
454 static void
455 babel_fill_with_next_timeout(struct timeval *tv)
456 {
457 #if (defined NO_DEBUG)
458 #define printIfMin(a,b,c,d)
459 #else
460 #define printIfMin(a,b,c,d) \
461 if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
462
463 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
464 struct interface *ifp = NULL;
465
466 *tv = check_neighbours_timeout;
467 printIfMin(tv, 0, "check_neighbours_timeout", NULL);
468 timeval_min_sec(tv, expiry_time);
469 printIfMin(tv, 1, "expiry_time", NULL);
470 timeval_min_sec(tv, source_expiry_time);
471 printIfMin(tv, 1, "source_expiry_time", NULL);
472 timeval_min(tv, &resend_time);
473 printIfMin(tv, 1, "resend_time", NULL);
474 FOR_ALL_INTERFACES(vrf, ifp) {
475 babel_interface_nfo *babel_ifp = NULL;
476 if(!if_up(ifp))
477 continue;
478 babel_ifp = babel_get_if_nfo(ifp);
479 timeval_min(tv, &babel_ifp->flush_timeout);
480 printIfMin(tv, 1, "flush_timeout", ifp->name);
481 timeval_min(tv, &babel_ifp->hello_timeout);
482 printIfMin(tv, 1, "hello_timeout", ifp->name);
483 timeval_min(tv, &babel_ifp->update_timeout);
484 printIfMin(tv, 1, "update_timeout", ifp->name);
485 timeval_min(tv, &babel_ifp->update_flush_timeout);
486 printIfMin(tv, 1, "update_flush_timeout",ifp->name);
487 }
488 timeval_min(tv, &unicast_flush_timeout);
489 printIfMin(tv, 1, "unicast_flush_timeout", NULL);
490 printIfMin(tv, 2, NULL, NULL);
491 #undef printIfMin
492 #endif
493 }
494
495 /* set the t_update thread of the babel routing process to be launch in
496 'timeout' (approximate at the milisecond) */
497 static void
498 babel_set_timer(struct timeval *timeout)
499 {
500 long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
501 if (babel_routing_process->t_update != NULL) {
502 thread_cancel(babel_routing_process->t_update);
503 }
504 thread_add_timer_msec(master, babel_main_loop, NULL, msecs, &babel_routing_process->t_update);
505 }
506
507 void
508 schedule_neighbours_check(int msecs, int override)
509 {
510 struct timeval timeout;
511
512 timeval_add_msec(&timeout, &babel_now, msecs);
513 if(override)
514 check_neighbours_timeout = timeout;
515 else
516 timeval_min(&check_neighbours_timeout, &timeout);
517 }
518
519 int
520 resize_receive_buffer(int size)
521 {
522 if(size <= receive_buffer_size)
523 return 0;
524
525 if(receive_buffer == NULL) {
526 receive_buffer = malloc(size);
527 if(receive_buffer == NULL) {
528 flog_err(EC_BABEL_MEMORY, "malloc(receive_buffer): %s",
529 safe_strerror(errno));
530 return -1;
531 }
532 receive_buffer_size = size;
533 } else {
534 unsigned char *new;
535 new = realloc(receive_buffer, size);
536 if(new == NULL) {
537 flog_err(EC_BABEL_MEMORY, "realloc(receive_buffer): %s",
538 safe_strerror(errno));
539 return -1;
540 }
541 receive_buffer = new;
542 receive_buffer_size = size;
543 }
544 return 1;
545 }
546
547 static void
548 babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist)
549 {
550 struct interface *ifp;
551 babel_interface_nfo *babel_ifp;
552 int type;
553 int family;
554
555 if (! dist->ifname)
556 return;
557
558 ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
559 if (ifp == NULL)
560 return;
561
562 babel_ifp = babel_get_if_nfo(ifp);
563
564 for (type = 0; type < DISTRIBUTE_MAX; type++) {
565 family = type == DISTRIBUTE_V4_IN || type == DISTRIBUTE_V4_OUT ?
566 AFI_IP : AFI_IP6;
567 if (dist->list[type])
568 babel_ifp->list[type] = access_list_lookup (family,
569 dist->list[type]);
570 else
571 babel_ifp->list[type] = NULL;
572 if (dist->prefix[type])
573 babel_ifp->prefix[type] = prefix_list_lookup (family,
574 dist->prefix[type]);
575 else
576 babel_ifp->prefix[type] = NULL;
577 }
578 }
579
580 static void
581 babel_distribute_update_interface (struct interface *ifp)
582 {
583 struct distribute *dist = NULL;
584
585 if (babel_routing_process)
586 dist = distribute_lookup(babel_routing_process->distribute_ctx, ifp->name);
587 if (dist)
588 babel_distribute_update (babel_routing_process->distribute_ctx, dist);
589 }
590
591 /* Update all interface's distribute list. */
592 static void
593 babel_distribute_update_all (struct prefix_list *notused)
594 {
595 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
596 struct interface *ifp;
597
598 FOR_ALL_INTERFACES (vrf, ifp)
599 babel_distribute_update_interface (ifp);
600 }
601
602 static void
603 babel_distribute_update_all_wrapper (struct access_list *notused)
604 {
605 babel_distribute_update_all(NULL);
606 }
607
608
609 /* [Command] */
610 DEFUN_NOSH (router_babel,
611 router_babel_cmd,
612 "router babel",
613 "Enable a routing process\n"
614 "Make Babel instance command\n")
615 {
616 int ret;
617
618 vty->node = BABEL_NODE;
619
620 if (!babel_routing_process) {
621 ret = babel_create_routing_process ();
622
623 /* Notice to user we couldn't create Babel. */
624 if (ret < 0) {
625 zlog_warn ("can't create Babel");
626 return CMD_WARNING;
627 }
628 }
629
630 return CMD_SUCCESS;
631 }
632
633 /* [Command] */
634 DEFUN (no_router_babel,
635 no_router_babel_cmd,
636 "no router babel",
637 NO_STR
638 "Disable a routing process\n"
639 "Remove Babel instance command\n")
640 {
641 if(babel_routing_process)
642 babel_clean_routing_process();
643 return CMD_SUCCESS;
644 }
645
646 /* [Babel Command] */
647 DEFUN (babel_diversity,
648 babel_diversity_cmd,
649 "babel diversity",
650 "Babel commands\n"
651 "Enable diversity-aware routing.\n")
652 {
653 diversity_kind = DIVERSITY_CHANNEL;
654 return CMD_SUCCESS;
655 }
656
657 /* [Babel Command] */
658 DEFUN (no_babel_diversity,
659 no_babel_diversity_cmd,
660 "no babel diversity",
661 NO_STR
662 "Babel commands\n"
663 "Disable diversity-aware routing.\n")
664 {
665 diversity_kind = DIVERSITY_NONE;
666 return CMD_SUCCESS;
667 }
668
669 /* [Babel Command] */
670 DEFUN (babel_diversity_factor,
671 babel_diversity_factor_cmd,
672 "babel diversity-factor (1-256)",
673 "Babel commands\n"
674 "Set the diversity factor.\n"
675 "Factor in units of 1/256.\n")
676 {
677 int factor;
678
679 factor = strtoul(argv[2]->arg, NULL, 10);
680
681 diversity_factor = factor;
682 return CMD_SUCCESS;
683 }
684
685 /* [Babel Command] */
686 DEFUN (babel_set_resend_delay,
687 babel_set_resend_delay_cmd,
688 "babel resend-delay (20-655340)",
689 "Babel commands\n"
690 "Time before resending a message\n"
691 "Milliseconds\n")
692 {
693 int interval;
694
695 interval = strtoul(argv[2]->arg, NULL, 10);
696
697 resend_delay = interval;
698 return CMD_SUCCESS;
699 }
700
701 /* [Babel Command] */
702 DEFUN (babel_set_smoothing_half_life,
703 babel_set_smoothing_half_life_cmd,
704 "babel smoothing-half-life (0-65534)",
705 "Babel commands\n"
706 "Smoothing half-life\n"
707 "Seconds (0 to disable)\n")
708 {
709 int seconds;
710
711 seconds = strtoul(argv[2]->arg, NULL, 10);
712
713 change_smoothing_half_life(seconds);
714 return CMD_SUCCESS;
715 }
716
717 void
718 babeld_quagga_init(void)
719 {
720
721 install_node(&cmd_babel_node, &babel_config_write);
722
723 install_element(CONFIG_NODE, &router_babel_cmd);
724 install_element(CONFIG_NODE, &no_router_babel_cmd);
725
726 install_default(BABEL_NODE);
727 install_element(BABEL_NODE, &babel_diversity_cmd);
728 install_element(BABEL_NODE, &no_babel_diversity_cmd);
729 install_element(BABEL_NODE, &babel_diversity_factor_cmd);
730 install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
731 install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
732
733 babel_if_init();
734
735 /* Access list install. */
736 access_list_init ();
737 access_list_add_hook (babel_distribute_update_all_wrapper);
738 access_list_delete_hook (babel_distribute_update_all_wrapper);
739
740 /* Prefix list initialize.*/
741 prefix_list_init ();
742 prefix_list_add_hook (babel_distribute_update_all);
743 prefix_list_delete_hook (babel_distribute_update_all);
744
745 /* Distribute list install. */
746 distribute_list_init(BABEL_NODE);
747 }
748
749 /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
750
751 int
752 input_filter(const unsigned char *id,
753 const unsigned char *prefix, unsigned short plen,
754 const unsigned char *neigh, unsigned int ifindex)
755 {
756 return babel_filter(0, prefix, plen, ifindex);
757 }
758
759 int
760 output_filter(const unsigned char *id, const unsigned char *prefix,
761 unsigned short plen, unsigned int ifindex)
762 {
763 return babel_filter(1, prefix, plen, ifindex);
764 }
765
766 /* There's no redistribute filter in Quagga -- the zebra daemon does its
767 own filtering. */
768 int
769 redistribute_filter(const unsigned char *prefix, unsigned short plen,
770 unsigned int ifindex, int proto)
771 {
772 return 0;
773 }
774
775 struct babel *babel_lookup(void)
776 {
777 return babel_routing_process;
778 }