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