]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babeld.c
Merge pull request #5060 from chiragshah6/evpn_dev2
[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 babel_routing_process = NULL;
169 return -1;
170 }
171
172 /* thread reading entries form others babel daemons */
173 static int
174 babel_read_protocol (struct thread *thread)
175 {
176 int rc;
177 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
178 struct interface *ifp = NULL;
179 struct sockaddr_in6 sin6;
180
181 assert(babel_routing_process != NULL);
182 assert(protocol_socket >= 0);
183
184 rc = babel_recv(protocol_socket,
185 receive_buffer, receive_buffer_size,
186 (struct sockaddr*)&sin6, sizeof(sin6));
187 if(rc < 0) {
188 if(errno != EAGAIN && errno != EINTR) {
189 flog_err_sys(EC_LIB_SOCKET, "recv: %s", safe_strerror(errno));
190 }
191 } else {
192 FOR_ALL_INTERFACES(vrf, ifp) {
193 if(!if_up(ifp))
194 continue;
195 if(ifp->ifindex == (ifindex_t)sin6.sin6_scope_id) {
196 parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
197 receive_buffer, rc);
198 break;
199 }
200 }
201 }
202
203 /* re-add thread */
204 thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
205 return 0;
206 }
207
208 /* Zebra will give some information, especially about interfaces. This function
209 must be call with a litte timeout wich may give zebra the time to do his job,
210 making these inits have sense. */
211 static int
212 babel_init_routing_process(struct thread *thread)
213 {
214 myseqno = (random() & 0xFFFF);
215 babel_get_myid();
216 babel_load_state_file();
217 debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
218 babel_initial_noise();
219 babel_main_loop(thread);/* this function self-add to the t_update thread */
220 return 0;
221 }
222
223 /* fill "myid" with an unique id (only if myid != {0}). */
224 static void
225 babel_get_myid(void)
226 {
227 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
228 struct interface *ifp = NULL;
229 int rc;
230 int i;
231
232 /* if we already have an id (from state file), we return. */
233 if (memcmp(myid, zeroes, 8) != 0) {
234 return;
235 }
236
237 FOR_ALL_INTERFACES(vrf, ifp) {
238 /* ifp->ifindex is not necessarily valid at this point */
239 int ifindex = if_nametoindex(ifp->name);
240 if(ifindex > 0) {
241 unsigned char eui[8];
242 rc = if_eui64(ifindex, eui);
243 if(rc < 0)
244 continue;
245 memcpy(myid, eui, 8);
246 return;
247 }
248 }
249
250 /* We failed to get a global EUI64 from the interfaces we were given.
251 Let's try to find an interface with a MAC address. */
252 for(i = 1; i < 256; i++) {
253 char buf[IF_NAMESIZE], *ifname;
254 unsigned char eui[8];
255 ifname = if_indextoname(i, buf);
256 if(ifname == NULL)
257 continue;
258 rc = if_eui64(i, eui);
259 if(rc < 0)
260 continue;
261 memcpy(myid, eui, 8);
262 return;
263 }
264
265 flog_err(EC_BABEL_CONFIG,
266 "Warning: couldn't find router id -- using random value.");
267
268 rc = read_random_bytes(myid, 8);
269 if(rc < 0) {
270 flog_err(EC_BABEL_CONFIG, "read(random): %s (cannot assign an ID)",
271 safe_strerror(errno));
272 exit(1);
273 }
274 /* Clear group and global bits */
275 myid[0] &= ~3;
276 }
277
278 /* Make some noise so that others notice us, and send retractions in
279 case we were restarted recently */
280 static void
281 babel_initial_noise(void)
282 {
283 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
284 struct interface *ifp = NULL;
285
286 FOR_ALL_INTERFACES(vrf, ifp) {
287 if(!if_up(ifp))
288 continue;
289 /* Apply jitter before we send the first message. */
290 usleep(roughly(10000));
291 gettime(&babel_now);
292 send_hello(ifp);
293 send_wildcard_retraction(ifp);
294 }
295
296 FOR_ALL_INTERFACES(vrf, ifp) {
297 if(!if_up(ifp))
298 continue;
299 usleep(roughly(10000));
300 gettime(&babel_now);
301 send_hello(ifp);
302 send_wildcard_retraction(ifp);
303 send_self_update(ifp);
304 send_request(ifp, NULL, 0);
305 flushupdates(ifp);
306 flushbuf(ifp);
307 }
308 }
309
310 /* Delete all the added babel routes, make babeld only speak to zebra. */
311 static void
312 babel_clean_routing_process(void)
313 {
314 flush_all_routes();
315 babel_interface_close_all();
316
317 /* cancel threads */
318 if (babel_routing_process->t_read != NULL) {
319 thread_cancel(babel_routing_process->t_read);
320 }
321 if (babel_routing_process->t_update != NULL) {
322 thread_cancel(babel_routing_process->t_update);
323 }
324
325 distribute_list_delete(&babel_routing_process->distribute_ctx);
326 XFREE(MTYPE_BABEL, babel_routing_process);
327 babel_routing_process = NULL;
328 }
329
330 /* Function used with timeout. */
331 static int
332 babel_main_loop(struct thread *thread)
333 {
334 struct timeval tv;
335 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
336 struct interface *ifp = NULL;
337
338 while(1) {
339 gettime(&babel_now);
340
341 /* timeouts --------------------------------------------------------- */
342 /* get the next timeout */
343 babel_fill_with_next_timeout(&tv);
344 /* if there is no timeout, we must wait. */
345 if(timeval_compare(&tv, &babel_now) > 0) {
346 timeval_minus(&tv, &tv, &babel_now);
347 debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs",
348 (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000);
349 /* it happens often to have less than 1 ms, it's bad. */
350 timeval_add_msec(&tv, &tv, 300);
351 babel_set_timer(&tv);
352 return 0;
353 }
354
355 gettime(&babel_now);
356
357 /* update database -------------------------------------------------- */
358 if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
359 int msecs;
360 msecs = check_neighbours();
361 /* Multiply by 3/2 to allow neighbours to expire. */
362 msecs = MAX(3 * msecs / 2, 10);
363 schedule_neighbours_check(msecs, 1);
364 }
365
366 if(babel_now.tv_sec >= expiry_time) {
367 expire_routes();
368 expire_resend();
369 expiry_time = babel_now.tv_sec + roughly(30);
370 }
371
372 if(babel_now.tv_sec >= source_expiry_time) {
373 expire_sources();
374 source_expiry_time = babel_now.tv_sec + roughly(300);
375 }
376
377 FOR_ALL_INTERFACES(vrf, ifp) {
378 babel_interface_nfo *babel_ifp = NULL;
379 if(!if_up(ifp))
380 continue;
381 babel_ifp = babel_get_if_nfo(ifp);
382 if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
383 send_hello(ifp);
384 if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
385 send_update(ifp, 0, NULL, 0);
386 if(timeval_compare(&babel_now,
387 &babel_ifp->update_flush_timeout) >= 0)
388 flushupdates(ifp);
389 }
390
391 if(resend_time.tv_sec != 0) {
392 if(timeval_compare(&babel_now, &resend_time) >= 0)
393 do_resend();
394 }
395
396 if(unicast_flush_timeout.tv_sec != 0) {
397 if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
398 flush_unicast(1);
399 }
400
401 FOR_ALL_INTERFACES(vrf, ifp) {
402 babel_interface_nfo *babel_ifp = NULL;
403 if(!if_up(ifp))
404 continue;
405 babel_ifp = babel_get_if_nfo(ifp);
406 if(babel_ifp->flush_timeout.tv_sec != 0) {
407 if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
408 flushbuf(ifp);
409 }
410 }
411 }
412
413 assert(0); /* this line should never be reach */
414 }
415
416 static void
417 printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
418 {
419 static struct timeval curr_tv;
420 static char buffer[200];
421 static const char *curr_tag = NULL;
422
423 switch (cmd) {
424 case 0: /* reset timeval */
425 curr_tv = *tv;
426 if(ifname != NULL) {
427 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
428 curr_tag = buffer;
429 } else {
430 curr_tag = tag;
431 }
432 break;
433 case 1: /* take the min */
434 if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
435 break;
436 }
437 if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
438 tv->tv_usec < curr_tv.tv_usec)) {
439 curr_tv = *tv;
440 if(ifname != NULL) {
441 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
442 curr_tag = buffer;
443 } else {
444 curr_tag = tag;
445 }
446 }
447 break;
448 case 2: /* print message */
449 debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
450 break;
451 default:
452 break;
453 }
454 }
455
456 static void
457 babel_fill_with_next_timeout(struct timeval *tv)
458 {
459 #if (defined NO_DEBUG)
460 #define printIfMin(a,b,c,d)
461 #else
462 #define printIfMin(a,b,c,d) \
463 if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
464
465 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
466 struct interface *ifp = NULL;
467
468 *tv = check_neighbours_timeout;
469 printIfMin(tv, 0, "check_neighbours_timeout", NULL);
470 timeval_min_sec(tv, expiry_time);
471 printIfMin(tv, 1, "expiry_time", NULL);
472 timeval_min_sec(tv, source_expiry_time);
473 printIfMin(tv, 1, "source_expiry_time", NULL);
474 timeval_min(tv, &resend_time);
475 printIfMin(tv, 1, "resend_time", NULL);
476 FOR_ALL_INTERFACES(vrf, ifp) {
477 babel_interface_nfo *babel_ifp = NULL;
478 if(!if_up(ifp))
479 continue;
480 babel_ifp = babel_get_if_nfo(ifp);
481 timeval_min(tv, &babel_ifp->flush_timeout);
482 printIfMin(tv, 1, "flush_timeout", ifp->name);
483 timeval_min(tv, &babel_ifp->hello_timeout);
484 printIfMin(tv, 1, "hello_timeout", ifp->name);
485 timeval_min(tv, &babel_ifp->update_timeout);
486 printIfMin(tv, 1, "update_timeout", ifp->name);
487 timeval_min(tv, &babel_ifp->update_flush_timeout);
488 printIfMin(tv, 1, "update_flush_timeout",ifp->name);
489 }
490 timeval_min(tv, &unicast_flush_timeout);
491 printIfMin(tv, 1, "unicast_flush_timeout", NULL);
492 printIfMin(tv, 2, NULL, NULL);
493 #undef printIfMin
494 #endif
495 }
496
497 /* set the t_update thread of the babel routing process to be launch in
498 'timeout' (approximate at the milisecond) */
499 static void
500 babel_set_timer(struct timeval *timeout)
501 {
502 long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
503 if (babel_routing_process->t_update != NULL) {
504 thread_cancel(babel_routing_process->t_update);
505 }
506 thread_add_timer_msec(master, babel_main_loop, NULL, msecs, &babel_routing_process->t_update);
507 }
508
509 void
510 schedule_neighbours_check(int msecs, int override)
511 {
512 struct timeval timeout;
513
514 timeval_add_msec(&timeout, &babel_now, msecs);
515 if(override)
516 check_neighbours_timeout = timeout;
517 else
518 timeval_min(&check_neighbours_timeout, &timeout);
519 }
520
521 int
522 resize_receive_buffer(int size)
523 {
524 if(size <= receive_buffer_size)
525 return 0;
526
527 if(receive_buffer == NULL) {
528 receive_buffer = malloc(size);
529 if(receive_buffer == NULL) {
530 flog_err(EC_BABEL_MEMORY, "malloc(receive_buffer): %s",
531 safe_strerror(errno));
532 return -1;
533 }
534 receive_buffer_size = size;
535 } else {
536 unsigned char *new;
537 new = realloc(receive_buffer, size);
538 if(new == NULL) {
539 flog_err(EC_BABEL_MEMORY, "realloc(receive_buffer): %s",
540 safe_strerror(errno));
541 return -1;
542 }
543 receive_buffer = new;
544 receive_buffer_size = size;
545 }
546 return 1;
547 }
548
549 static void
550 babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist)
551 {
552 struct interface *ifp;
553 babel_interface_nfo *babel_ifp;
554 int type;
555 int family;
556
557 if (! dist->ifname)
558 return;
559
560 ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
561 if (ifp == NULL)
562 return;
563
564 babel_ifp = babel_get_if_nfo(ifp);
565
566 for (type = 0; type < DISTRIBUTE_MAX; type++) {
567 family = type == DISTRIBUTE_V4_IN || type == DISTRIBUTE_V4_OUT ?
568 AFI_IP : AFI_IP6;
569 if (dist->list[type])
570 babel_ifp->list[type] = access_list_lookup (family,
571 dist->list[type]);
572 else
573 babel_ifp->list[type] = NULL;
574 if (dist->prefix[type])
575 babel_ifp->prefix[type] = prefix_list_lookup (family,
576 dist->prefix[type]);
577 else
578 babel_ifp->prefix[type] = NULL;
579 }
580 }
581
582 static void
583 babel_distribute_update_interface (struct interface *ifp)
584 {
585 struct distribute *dist = NULL;
586
587 if (babel_routing_process)
588 dist = distribute_lookup(babel_routing_process->distribute_ctx, ifp->name);
589 if (dist)
590 babel_distribute_update (babel_routing_process->distribute_ctx, dist);
591 }
592
593 /* Update all interface's distribute list. */
594 static void
595 babel_distribute_update_all (struct prefix_list *notused)
596 {
597 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
598 struct interface *ifp;
599
600 FOR_ALL_INTERFACES (vrf, ifp)
601 babel_distribute_update_interface (ifp);
602 }
603
604 static void
605 babel_distribute_update_all_wrapper (struct access_list *notused)
606 {
607 babel_distribute_update_all(NULL);
608 }
609
610
611 /* [Command] */
612 DEFUN_NOSH (router_babel,
613 router_babel_cmd,
614 "router babel",
615 "Enable a routing process\n"
616 "Make Babel instance command\n")
617 {
618 int ret;
619
620 vty->node = BABEL_NODE;
621
622 if (!babel_routing_process) {
623 ret = babel_create_routing_process ();
624
625 /* Notice to user we couldn't create Babel. */
626 if (ret < 0) {
627 zlog_warn ("can't create Babel");
628 return CMD_WARNING;
629 }
630 }
631
632 return CMD_SUCCESS;
633 }
634
635 /* [Command] */
636 DEFUN (no_router_babel,
637 no_router_babel_cmd,
638 "no router babel",
639 NO_STR
640 "Disable a routing process\n"
641 "Remove Babel instance command\n")
642 {
643 if(babel_routing_process)
644 babel_clean_routing_process();
645 return CMD_SUCCESS;
646 }
647
648 /* [Babel Command] */
649 DEFUN (babel_diversity,
650 babel_diversity_cmd,
651 "babel diversity",
652 "Babel commands\n"
653 "Enable diversity-aware routing.\n")
654 {
655 diversity_kind = DIVERSITY_CHANNEL;
656 return CMD_SUCCESS;
657 }
658
659 /* [Babel Command] */
660 DEFUN (no_babel_diversity,
661 no_babel_diversity_cmd,
662 "no babel diversity",
663 NO_STR
664 "Babel commands\n"
665 "Disable diversity-aware routing.\n")
666 {
667 diversity_kind = DIVERSITY_NONE;
668 return CMD_SUCCESS;
669 }
670
671 /* [Babel Command] */
672 DEFUN (babel_diversity_factor,
673 babel_diversity_factor_cmd,
674 "babel diversity-factor (1-256)",
675 "Babel commands\n"
676 "Set the diversity factor.\n"
677 "Factor in units of 1/256.\n")
678 {
679 int factor;
680
681 factor = strtoul(argv[2]->arg, NULL, 10);
682
683 diversity_factor = factor;
684 return CMD_SUCCESS;
685 }
686
687 /* [Babel Command] */
688 DEFUN (babel_set_resend_delay,
689 babel_set_resend_delay_cmd,
690 "babel resend-delay (20-655340)",
691 "Babel commands\n"
692 "Time before resending a message\n"
693 "Milliseconds\n")
694 {
695 int interval;
696
697 interval = strtoul(argv[2]->arg, NULL, 10);
698
699 resend_delay = interval;
700 return CMD_SUCCESS;
701 }
702
703 /* [Babel Command] */
704 DEFUN (babel_set_smoothing_half_life,
705 babel_set_smoothing_half_life_cmd,
706 "babel smoothing-half-life (0-65534)",
707 "Babel commands\n"
708 "Smoothing half-life\n"
709 "Seconds (0 to disable)\n")
710 {
711 int seconds;
712
713 seconds = strtoul(argv[2]->arg, NULL, 10);
714
715 change_smoothing_half_life(seconds);
716 return CMD_SUCCESS;
717 }
718
719 void
720 babeld_quagga_init(void)
721 {
722
723 install_node(&cmd_babel_node, &babel_config_write);
724
725 install_element(CONFIG_NODE, &router_babel_cmd);
726 install_element(CONFIG_NODE, &no_router_babel_cmd);
727
728 install_default(BABEL_NODE);
729 install_element(BABEL_NODE, &babel_diversity_cmd);
730 install_element(BABEL_NODE, &no_babel_diversity_cmd);
731 install_element(BABEL_NODE, &babel_diversity_factor_cmd);
732 install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
733 install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
734
735 babel_if_init();
736
737 /* Access list install. */
738 access_list_init ();
739 access_list_add_hook (babel_distribute_update_all_wrapper);
740 access_list_delete_hook (babel_distribute_update_all_wrapper);
741
742 /* Prefix list initialize.*/
743 prefix_list_init ();
744 prefix_list_add_hook (babel_distribute_update_all);
745 prefix_list_delete_hook (babel_distribute_update_all);
746
747 /* Distribute list install. */
748 distribute_list_init(BABEL_NODE);
749 }
750
751 /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
752
753 int
754 input_filter(const unsigned char *id,
755 const unsigned char *prefix, unsigned short plen,
756 const unsigned char *neigh, unsigned int ifindex)
757 {
758 return babel_filter(0, prefix, plen, ifindex);
759 }
760
761 int
762 output_filter(const unsigned char *id, const unsigned char *prefix,
763 unsigned short plen, unsigned int ifindex)
764 {
765 return babel_filter(1, prefix, plen, ifindex);
766 }
767
768 /* There's no redistribute filter in Quagga -- the zebra daemon does its
769 own filtering. */
770 int
771 redistribute_filter(const unsigned char *prefix, unsigned short plen,
772 unsigned int ifindex, int proto)
773 {
774 return 0;
775 }
776
777 struct babel *babel_lookup(void)
778 {
779 return babel_routing_process;
780 }