]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babeld.c
Merge pull request #5805 from donaldsharp/babel_int_return
[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_errors.h"
47
48 DEFINE_MGROUP(BABELD, "babeld")
49 DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure")
50
51 static int babel_init_routing_process(struct thread *thread);
52 static void babel_get_myid(void);
53 static void babel_initial_noise(void);
54 static int babel_read_protocol (struct thread *thread);
55 static int babel_main_loop(struct thread *thread);
56 static void babel_set_timer(struct timeval *timeout);
57 static void babel_fill_with_next_timeout(struct timeval *tv);
58 static void
59 babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist);
60
61 /* Informations relative to the babel running daemon. */
62 static struct babel *babel_routing_process = NULL;
63 static unsigned char *receive_buffer = NULL;
64 static int receive_buffer_size = 0;
65
66 /* timeouts */
67 struct timeval check_neighbours_timeout;
68 static time_t expiry_time;
69 static time_t source_expiry_time;
70
71 /* Babel node structure. */
72 static struct cmd_node cmd_babel_node =
73 {
74 .node = BABEL_NODE,
75 .prompt = "%s(config-router)# ",
76 .vtysh = 1,
77 };
78
79 /* print current babel configuration on vty */
80 static int
81 babel_config_write (struct vty *vty)
82 {
83 int lines = 0;
84 int afi;
85 int i;
86
87 /* list enabled debug modes */
88 lines += debug_babel_config_write (vty);
89
90 if (!babel_routing_process)
91 return lines;
92 vty_out (vty, "router babel\n");
93 if (diversity_kind != DIVERSITY_NONE)
94 {
95 vty_out (vty, " babel diversity\n");
96 lines++;
97 }
98 if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
99 {
100 vty_out (vty, " babel diversity-factor %d\n",diversity_factor);
101 lines++;
102 }
103 if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
104 {
105 vty_out (vty, " babel resend-delay %u\n", resend_delay);
106 lines++;
107 }
108 if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
109 {
110 vty_out (vty, " babel smoothing-half-life %u\n",
111 smoothing_half_life);
112 lines++;
113 }
114 /* list enabled interfaces */
115 lines = 1 + babel_enable_if_config_write (vty);
116 /* list redistributed protocols */
117 for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
118 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
119 if (i != zclient->redist_default &&
120 vrf_bitmap_check (zclient->redist[afi][i], VRF_DEFAULT)) {
121 vty_out (vty, " redistribute %s %s\n",
122 (afi == AFI_IP) ? "ipv4" : "ipv6",
123 zebra_route_string(i));
124 lines++;
125 }
126 }
127 }
128
129 lines += config_write_distribute (vty, babel_routing_process->distribute_ctx);
130
131 return lines;
132 }
133
134
135 static int
136 babel_create_routing_process (void)
137 {
138 assert (babel_routing_process == NULL);
139
140 /* Allocaste Babel instance. */
141 babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel));
142
143 /* Initialize timeouts */
144 gettime(&babel_now);
145 expiry_time = babel_now.tv_sec + roughly(30);
146 source_expiry_time = babel_now.tv_sec + roughly(300);
147
148 /* Make socket for Babel protocol. */
149 protocol_socket = babel_socket(protocol_port);
150 if (protocol_socket < 0) {
151 flog_err_sys(EC_LIB_SOCKET, "Couldn't create link local socket: %s",
152 safe_strerror(errno));
153 goto fail;
154 }
155
156 /* Threads. */
157 thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
158 /* wait a little: zebra will announce interfaces, addresses, routes... */
159 thread_add_timer_msec(master, babel_init_routing_process, NULL, 200L, &babel_routing_process->t_update);
160
161 /* Distribute list install. */
162 babel_routing_process->distribute_ctx = distribute_list_ctx_create (vrf_lookup_by_id(VRF_DEFAULT));
163 distribute_list_add_hook (babel_routing_process->distribute_ctx, babel_distribute_update);
164 distribute_list_delete_hook (babel_routing_process->distribute_ctx, babel_distribute_update);
165 return 0;
166 fail:
167 XFREE(MTYPE_BABEL, babel_routing_process);
168 return -1;
169 }
170
171 /* thread reading entries form others babel daemons */
172 static int
173 babel_read_protocol (struct thread *thread)
174 {
175 int rc;
176 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
177 struct interface *ifp = NULL;
178 struct sockaddr_in6 sin6;
179
180 assert(babel_routing_process != NULL);
181 assert(protocol_socket >= 0);
182
183 rc = babel_recv(protocol_socket,
184 receive_buffer, receive_buffer_size,
185 (struct sockaddr*)&sin6, sizeof(sin6));
186 if(rc < 0) {
187 if(errno != EAGAIN && errno != EINTR) {
188 flog_err_sys(EC_LIB_SOCKET, "recv: %s", safe_strerror(errno));
189 }
190 } else {
191 FOR_ALL_INTERFACES(vrf, ifp) {
192 if(!if_up(ifp))
193 continue;
194 if(ifp->ifindex == (ifindex_t)sin6.sin6_scope_id) {
195 parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
196 receive_buffer, rc);
197 break;
198 }
199 }
200 }
201
202 /* re-add thread */
203 thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
204 return 0;
205 }
206
207 /* Zebra will give some information, especially about interfaces. This function
208 must be call with a litte timeout wich may give zebra the time to do his job,
209 making these inits have sense. */
210 static int
211 babel_init_routing_process(struct thread *thread)
212 {
213 myseqno = (random() & 0xFFFF);
214 babel_get_myid();
215 babel_load_state_file();
216 debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
217 babel_initial_noise();
218 babel_main_loop(thread);/* this function self-add to the t_update thread */
219 return 0;
220 }
221
222 /* fill "myid" with an unique id (only if myid != {0}). */
223 static void
224 babel_get_myid(void)
225 {
226 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
227 struct interface *ifp = NULL;
228 int rc;
229 int i;
230
231 /* if we already have an id (from state file), we return. */
232 if (memcmp(myid, zeroes, 8) != 0) {
233 return;
234 }
235
236 FOR_ALL_INTERFACES(vrf, ifp) {
237 /* ifp->ifindex is not necessarily valid at this point */
238 int ifindex = if_nametoindex(ifp->name);
239 if(ifindex > 0) {
240 unsigned char eui[8];
241 rc = if_eui64(ifindex, eui);
242 if(rc < 0)
243 continue;
244 memcpy(myid, eui, 8);
245 return;
246 }
247 }
248
249 /* We failed to get a global EUI64 from the interfaces we were given.
250 Let's try to find an interface with a MAC address. */
251 for(i = 1; i < 256; i++) {
252 char buf[IF_NAMESIZE], *ifname;
253 unsigned char eui[8];
254 ifname = if_indextoname(i, buf);
255 if(ifname == NULL)
256 continue;
257 rc = if_eui64(i, eui);
258 if(rc < 0)
259 continue;
260 memcpy(myid, eui, 8);
261 return;
262 }
263
264 flog_err(EC_BABEL_CONFIG,
265 "Warning: couldn't find router id -- using random value.");
266
267 rc = read_random_bytes(myid, 8);
268 if(rc < 0) {
269 flog_err(EC_BABEL_CONFIG, "read(random): %s (cannot assign an ID)",
270 safe_strerror(errno));
271 exit(1);
272 }
273 /* Clear group and global bits */
274 myid[0] &= ~3;
275 }
276
277 /* Make some noise so that others notice us, and send retractions in
278 case we were restarted recently */
279 static void
280 babel_initial_noise(void)
281 {
282 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
283 struct interface *ifp = NULL;
284
285 FOR_ALL_INTERFACES(vrf, ifp) {
286 if(!if_up(ifp))
287 continue;
288 /* Apply jitter before we send the first message. */
289 usleep(roughly(10000));
290 gettime(&babel_now);
291 send_hello(ifp);
292 send_wildcard_retraction(ifp);
293 }
294
295 FOR_ALL_INTERFACES(vrf, ifp) {
296 if(!if_up(ifp))
297 continue;
298 usleep(roughly(10000));
299 gettime(&babel_now);
300 send_hello(ifp);
301 send_wildcard_retraction(ifp);
302 send_self_update(ifp);
303 send_request(ifp, NULL, 0);
304 flushupdates(ifp);
305 flushbuf(ifp);
306 }
307 }
308
309 /* Delete all the added babel routes, make babeld only speak to zebra. */
310 static void
311 babel_clean_routing_process(void)
312 {
313 flush_all_routes();
314 babel_interface_close_all();
315
316 /* cancel threads */
317 if (babel_routing_process->t_read != NULL) {
318 thread_cancel(babel_routing_process->t_read);
319 }
320 if (babel_routing_process->t_update != NULL) {
321 thread_cancel(babel_routing_process->t_update);
322 }
323
324 distribute_list_delete(&babel_routing_process->distribute_ctx);
325 XFREE(MTYPE_BABEL, babel_routing_process);
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 return 0;
413 }
414
415 static void
416 printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
417 {
418 static struct timeval curr_tv;
419 static char buffer[200];
420 static const char *curr_tag = NULL;
421
422 switch (cmd) {
423 case 0: /* reset timeval */
424 curr_tv = *tv;
425 if(ifname != NULL) {
426 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
427 curr_tag = buffer;
428 } else {
429 curr_tag = tag;
430 }
431 break;
432 case 1: /* take the min */
433 if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
434 break;
435 }
436 if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
437 tv->tv_usec < curr_tv.tv_usec)) {
438 curr_tv = *tv;
439 if(ifname != NULL) {
440 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
441 curr_tag = buffer;
442 } else {
443 curr_tag = tag;
444 }
445 }
446 break;
447 case 2: /* print message */
448 debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
449 break;
450 default:
451 break;
452 }
453 }
454
455 static void
456 babel_fill_with_next_timeout(struct timeval *tv)
457 {
458 #if (defined NO_DEBUG)
459 #define printIfMin(a,b,c,d)
460 #else
461 #define printIfMin(a,b,c,d) \
462 if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
463
464 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
465 struct interface *ifp = NULL;
466
467 *tv = check_neighbours_timeout;
468 printIfMin(tv, 0, "check_neighbours_timeout", NULL);
469 timeval_min_sec(tv, expiry_time);
470 printIfMin(tv, 1, "expiry_time", NULL);
471 timeval_min_sec(tv, source_expiry_time);
472 printIfMin(tv, 1, "source_expiry_time", NULL);
473 timeval_min(tv, &resend_time);
474 printIfMin(tv, 1, "resend_time", NULL);
475 FOR_ALL_INTERFACES(vrf, ifp) {
476 babel_interface_nfo *babel_ifp = NULL;
477 if(!if_up(ifp))
478 continue;
479 babel_ifp = babel_get_if_nfo(ifp);
480 timeval_min(tv, &babel_ifp->flush_timeout);
481 printIfMin(tv, 1, "flush_timeout", ifp->name);
482 timeval_min(tv, &babel_ifp->hello_timeout);
483 printIfMin(tv, 1, "hello_timeout", ifp->name);
484 timeval_min(tv, &babel_ifp->update_timeout);
485 printIfMin(tv, 1, "update_timeout", ifp->name);
486 timeval_min(tv, &babel_ifp->update_flush_timeout);
487 printIfMin(tv, 1, "update_flush_timeout",ifp->name);
488 }
489 timeval_min(tv, &unicast_flush_timeout);
490 printIfMin(tv, 1, "unicast_flush_timeout", NULL);
491 printIfMin(tv, 2, NULL, NULL);
492 #undef printIfMin
493 #endif
494 }
495
496 /* set the t_update thread of the babel routing process to be launch in
497 'timeout' (approximate at the milisecond) */
498 static void
499 babel_set_timer(struct timeval *timeout)
500 {
501 long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
502 if (babel_routing_process->t_update != NULL) {
503 thread_cancel(babel_routing_process->t_update);
504 }
505 thread_add_timer_msec(master, babel_main_loop, NULL, msecs, &babel_routing_process->t_update);
506 }
507
508 void
509 schedule_neighbours_check(int msecs, int override)
510 {
511 struct timeval timeout;
512
513 timeval_add_msec(&timeout, &babel_now, msecs);
514 if(override)
515 check_neighbours_timeout = timeout;
516 else
517 timeval_min(&check_neighbours_timeout, &timeout);
518 }
519
520 int
521 resize_receive_buffer(int size)
522 {
523 if(size <= receive_buffer_size)
524 return 0;
525
526 if(receive_buffer == NULL) {
527 receive_buffer = malloc(size);
528 if(receive_buffer == NULL) {
529 flog_err(EC_BABEL_MEMORY, "malloc(receive_buffer): %s",
530 safe_strerror(errno));
531 return -1;
532 }
533 receive_buffer_size = size;
534 } else {
535 unsigned char *new;
536 new = realloc(receive_buffer, size);
537 if(new == NULL) {
538 flog_err(EC_BABEL_MEMORY, "realloc(receive_buffer): %s",
539 safe_strerror(errno));
540 return -1;
541 }
542 receive_buffer = new;
543 receive_buffer_size = size;
544 }
545 return 1;
546 }
547
548 static void
549 babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist)
550 {
551 struct interface *ifp;
552 babel_interface_nfo *babel_ifp;
553 int type;
554 int family;
555
556 if (! dist->ifname)
557 return;
558
559 ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
560 if (ifp == NULL)
561 return;
562
563 babel_ifp = babel_get_if_nfo(ifp);
564
565 for (type = 0; type < DISTRIBUTE_MAX; type++) {
566 family = type == DISTRIBUTE_V4_IN || type == DISTRIBUTE_V4_OUT ?
567 AFI_IP : AFI_IP6;
568 if (dist->list[type])
569 babel_ifp->list[type] = access_list_lookup (family,
570 dist->list[type]);
571 else
572 babel_ifp->list[type] = NULL;
573 if (dist->prefix[type])
574 babel_ifp->prefix[type] = prefix_list_lookup (family,
575 dist->prefix[type]);
576 else
577 babel_ifp->prefix[type] = NULL;
578 }
579 }
580
581 static void
582 babel_distribute_update_interface (struct interface *ifp)
583 {
584 struct distribute *dist = NULL;
585
586 if (babel_routing_process)
587 dist = distribute_lookup(babel_routing_process->distribute_ctx, ifp->name);
588 if (dist)
589 babel_distribute_update (babel_routing_process->distribute_ctx, dist);
590 }
591
592 /* Update all interface's distribute list. */
593 static void
594 babel_distribute_update_all (struct prefix_list *notused)
595 {
596 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
597 struct interface *ifp;
598
599 FOR_ALL_INTERFACES (vrf, ifp)
600 babel_distribute_update_interface (ifp);
601 }
602
603 static void
604 babel_distribute_update_all_wrapper (struct access_list *notused)
605 {
606 babel_distribute_update_all(NULL);
607 }
608
609
610 /* [Command] */
611 DEFUN_NOSH (router_babel,
612 router_babel_cmd,
613 "router babel",
614 "Enable a routing process\n"
615 "Make Babel instance command\n")
616 {
617 int ret;
618
619 vty->node = BABEL_NODE;
620
621 if (!babel_routing_process) {
622 ret = babel_create_routing_process ();
623
624 /* Notice to user we couldn't create Babel. */
625 if (ret < 0) {
626 zlog_warn ("can't create Babel");
627 return CMD_WARNING;
628 }
629 }
630
631 return CMD_SUCCESS;
632 }
633
634 /* [Command] */
635 DEFUN (no_router_babel,
636 no_router_babel_cmd,
637 "no router babel",
638 NO_STR
639 "Disable a routing process\n"
640 "Remove Babel instance command\n")
641 {
642 if(babel_routing_process)
643 babel_clean_routing_process();
644 return CMD_SUCCESS;
645 }
646
647 /* [Babel Command] */
648 DEFUN (babel_diversity,
649 babel_diversity_cmd,
650 "babel diversity",
651 "Babel commands\n"
652 "Enable diversity-aware routing.\n")
653 {
654 diversity_kind = DIVERSITY_CHANNEL;
655 return CMD_SUCCESS;
656 }
657
658 /* [Babel Command] */
659 DEFUN (no_babel_diversity,
660 no_babel_diversity_cmd,
661 "no babel diversity",
662 NO_STR
663 "Babel commands\n"
664 "Disable diversity-aware routing.\n")
665 {
666 diversity_kind = DIVERSITY_NONE;
667 return CMD_SUCCESS;
668 }
669
670 /* [Babel Command] */
671 DEFUN (babel_diversity_factor,
672 babel_diversity_factor_cmd,
673 "babel diversity-factor (1-256)",
674 "Babel commands\n"
675 "Set the diversity factor.\n"
676 "Factor in units of 1/256.\n")
677 {
678 int factor;
679
680 factor = strtoul(argv[2]->arg, NULL, 10);
681
682 diversity_factor = factor;
683 return CMD_SUCCESS;
684 }
685
686 /* [Babel Command] */
687 DEFUN (babel_set_resend_delay,
688 babel_set_resend_delay_cmd,
689 "babel resend-delay (20-655340)",
690 "Babel commands\n"
691 "Time before resending a message\n"
692 "Milliseconds\n")
693 {
694 int interval;
695
696 interval = strtoul(argv[2]->arg, NULL, 10);
697
698 resend_delay = interval;
699 return CMD_SUCCESS;
700 }
701
702 /* [Babel Command] */
703 DEFUN (babel_set_smoothing_half_life,
704 babel_set_smoothing_half_life_cmd,
705 "babel smoothing-half-life (0-65534)",
706 "Babel commands\n"
707 "Smoothing half-life\n"
708 "Seconds (0 to disable)\n")
709 {
710 int seconds;
711
712 seconds = strtoul(argv[2]->arg, NULL, 10);
713
714 change_smoothing_half_life(seconds);
715 return CMD_SUCCESS;
716 }
717
718 void
719 babeld_quagga_init(void)
720 {
721
722 install_node(&cmd_babel_node, &babel_config_write);
723
724 install_element(CONFIG_NODE, &router_babel_cmd);
725 install_element(CONFIG_NODE, &no_router_babel_cmd);
726
727 install_default(BABEL_NODE);
728 install_element(BABEL_NODE, &babel_diversity_cmd);
729 install_element(BABEL_NODE, &no_babel_diversity_cmd);
730 install_element(BABEL_NODE, &babel_diversity_factor_cmd);
731 install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
732 install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
733
734 babel_if_init();
735
736 /* Access list install. */
737 access_list_init ();
738 access_list_add_hook (babel_distribute_update_all_wrapper);
739 access_list_delete_hook (babel_distribute_update_all_wrapper);
740
741 /* Prefix list initialize.*/
742 prefix_list_init ();
743 prefix_list_add_hook (babel_distribute_update_all);
744 prefix_list_delete_hook (babel_distribute_update_all);
745
746 /* Distribute list install. */
747 distribute_list_init(BABEL_NODE);
748 }
749
750 /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
751
752 int
753 input_filter(const unsigned char *id,
754 const unsigned char *prefix, unsigned short plen,
755 const unsigned char *neigh, unsigned int ifindex)
756 {
757 return babel_filter(0, prefix, plen, ifindex);
758 }
759
760 int
761 output_filter(const unsigned char *id, const unsigned char *prefix,
762 unsigned short plen, unsigned int ifindex)
763 {
764 return babel_filter(1, prefix, plen, ifindex);
765 }
766
767 /* There's no redistribute filter in Quagga -- the zebra daemon does its
768 own filtering. */
769 int
770 redistribute_filter(const unsigned char *prefix, unsigned short plen,
771 unsigned int ifindex, int proto)
772 {
773 return 0;
774 }
775
776 struct babel *babel_lookup(void)
777 {
778 return babel_routing_process;
779 }