]> git.proxmox.com Git - mirror_frr.git/blame - babeld/babeld.c
Merge pull request #4525 from donaldsharp/some_cleanups
[mirror_frr.git] / babeld / babeld.c
CommitLineData
ca10883e
DS
1/*
2Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE 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"
f135ba52 32#include "lib_errors.h"
ca10883e
DS
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"
f135ba52 46#include "babel_errors.h"
ca10883e 47
8b7454e9
DL
48DEFINE_MGROUP(BABELD, "babeld")
49DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure")
50
ca10883e
DS
51static int babel_init_routing_process(struct thread *thread);
52static void babel_get_myid(void);
53static void babel_initial_noise(void);
54static int babel_read_protocol (struct thread *thread);
55static int babel_main_loop(struct thread *thread);
56static void babel_set_timer(struct timeval *timeout);
57static void babel_fill_with_next_timeout(struct timeval *tv);
03a38493
PG
58static void
59babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist);
ca10883e
DS
60
61/* Informations relative to the babel running daemon. */
62static struct babel *babel_routing_process = NULL;
63static unsigned char *receive_buffer = NULL;
64static int receive_buffer_size = 0;
65
66/* timeouts */
67struct timeval check_neighbours_timeout;
68static time_t expiry_time;
69static time_t source_expiry_time;
70
71/* Babel node structure. */
72static 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 */
80static int
81babel_config_write (struct vty *vty)
82{
83 int lines = 0;
dd8765ca 84 int afi;
ca10883e
DS
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;
5c7571d4 92 vty_out (vty, "router babel\n");
ca10883e
DS
93 if (diversity_kind != DIVERSITY_NONE)
94 {
5c7571d4 95 vty_out (vty, " babel diversity\n");
ca10883e
DS
96 lines++;
97 }
98 if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
99 {
5c7571d4 100 vty_out (vty, " babel diversity-factor %d\n",diversity_factor);
ca10883e
DS
101 lines++;
102 }
103 if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
104 {
5c7571d4 105 vty_out (vty, " babel resend-delay %u\n", resend_delay);
ca10883e
DS
106 lines++;
107 }
108 if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
109 {
5c7571d4 110 vty_out (vty, " babel smoothing-half-life %u\n",
96ade3ed 111 smoothing_half_life);
ca10883e
DS
112 lines++;
113 }
114 /* list enabled interfaces */
115 lines = 1 + babel_enable_if_config_write (vty);
116 /* list redistributed protocols */
dd8765ca
RW
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 }
ca10883e 126 }
dd8765ca 127 }
ca10883e 128
03a38493 129 lines += config_write_distribute (vty, babel_routing_process->distribute_ctx);
ca10883e
DS
130
131 return lines;
132}
133
134
135static int
136babel_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) {
450971aa 151 flog_err_sys(EC_LIB_SOCKET, "Couldn't create link local socket: %s",
f135ba52 152 safe_strerror(errno));
ca10883e
DS
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);
ca10883e 160
03a38493
PG
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;
ca10883e
DS
166fail:
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 */
173static int
174babel_read_protocol (struct thread *thread)
175{
176 int rc;
f4e14fdb 177 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e
DS
178 struct interface *ifp = NULL;
179 struct sockaddr_in6 sin6;
ca10883e
DS
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) {
450971aa 189 flog_err_sys(EC_LIB_SOCKET, "recv: %s", safe_strerror(errno));
ca10883e
DS
190 }
191 } else {
f4e14fdb 192 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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. */
211static int
212babel_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}). */
224static void
225babel_get_myid(void)
226{
f4e14fdb 227 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 228 struct interface *ifp = NULL;
ca10883e
DS
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
f4e14fdb 237 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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];
edb1d4a0 242 rc = if_eui64(ifindex, eui);
ca10883e
DS
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;
edb1d4a0 258 rc = if_eui64(i, eui);
ca10883e
DS
259 if(rc < 0)
260 continue;
261 memcpy(myid, eui, 8);
262 return;
263 }
264
5b003f31 265 flog_err(EC_BABEL_CONFIG,
e33b116c 266 "Warning: couldn't find router id -- using random value.");
ca10883e
DS
267
268 rc = read_random_bytes(myid, 8);
269 if(rc < 0) {
5b003f31 270 flog_err(EC_BABEL_CONFIG, "read(random): %s (cannot assign an ID)",
e33b116c 271 safe_strerror(errno));
ca10883e
DS
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 */
280static void
281babel_initial_noise(void)
282{
f4e14fdb 283 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 284 struct interface *ifp = NULL;
ca10883e 285
f4e14fdb 286 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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
f4e14fdb 296 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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. */
311static void
4d762f26 312babel_clean_routing_process(void)
ca10883e
DS
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
03a38493 325 distribute_list_delete(&babel_routing_process->distribute_ctx);
ca10883e
DS
326 XFREE(MTYPE_BABEL, babel_routing_process);
327 babel_routing_process = NULL;
328}
329
330/* Function used with timeout. */
331static int
332babel_main_loop(struct thread *thread)
333{
334 struct timeval tv;
f4e14fdb 335 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 336 struct interface *ifp = NULL;
ca10883e
DS
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);
a97986ff
DL
347 debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs",
348 (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000);
ca10883e
DS
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
f4e14fdb 377 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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
f4e14fdb 401 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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
416static void
417printIfMin(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
456static void
457babel_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
f4e14fdb 465 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 466 struct interface *ifp = NULL;
ca10883e
DS
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);
f4e14fdb 476 FOR_ALL_INTERFACES(vrf, ifp) {
ca10883e
DS
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) */
499static void
500babel_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
509void
510schedule_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
521int
522resize_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) {
5b003f31 530 flog_err(EC_BABEL_MEMORY, "malloc(receive_buffer): %s",
f135ba52 531 safe_strerror(errno));
ca10883e
DS
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) {
5b003f31 539 flog_err(EC_BABEL_MEMORY, "realloc(receive_buffer): %s",
f135ba52 540 safe_strerror(errno));
ca10883e
DS
541 return -1;
542 }
543 receive_buffer = new;
544 receive_buffer_size = size;
545 }
546 return 1;
547}
548
549static void
03a38493 550babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist)
ca10883e
DS
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
a36898e7 560 ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
ca10883e
DS
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
582static void
583babel_distribute_update_interface (struct interface *ifp)
584{
03a38493 585 struct distribute *dist = NULL;
ca10883e 586
03a38493
PG
587 if (babel_routing_process)
588 dist = distribute_lookup(babel_routing_process->distribute_ctx, ifp->name);
ca10883e 589 if (dist)
03a38493 590 babel_distribute_update (babel_routing_process->distribute_ctx, dist);
ca10883e
DS
591}
592
593/* Update all interface's distribute list. */
594static void
595babel_distribute_update_all (struct prefix_list *notused)
596{
f4e14fdb 597 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
ca10883e 598 struct interface *ifp;
ca10883e 599
451fda4f 600 FOR_ALL_INTERFACES (vrf, ifp)
ca10883e
DS
601 babel_distribute_update_interface (ifp);
602}
603
604static void
605babel_distribute_update_all_wrapper (struct access_list *notused)
606{
607 babel_distribute_update_all(NULL);
608}
609
610
611/* [Command] */
f84d11d1
DS
612DEFUN_NOSH (router_babel,
613 router_babel_cmd,
614 "router babel",
615 "Enable a routing process\n"
616 "Make Babel instance command\n")
ca10883e
DS
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] */
636DEFUN (no_router_babel,
637 no_router_babel_cmd,
638 "no router babel",
639 NO_STR
640 "Disable a routing process\n"
7111c1a0 641 "Remove Babel instance command\n")
ca10883e
DS
642{
643 if(babel_routing_process)
644 babel_clean_routing_process();
645 return CMD_SUCCESS;
646}
647
648/* [Babel Command] */
649DEFUN (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] */
660DEFUN (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] */
672DEFUN (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
facfee22 681 factor = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
682
683 diversity_factor = factor;
684 return CMD_SUCCESS;
685}
686
687/* [Babel Command] */
688DEFUN (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
facfee22 697 interval = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
698
699 resend_delay = interval;
700 return CMD_SUCCESS;
701}
702
703/* [Babel Command] */
704DEFUN (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
facfee22 713 seconds = strtoul(argv[2]->arg, NULL, 10);
ca10883e
DS
714
715 change_smoothing_half_life(seconds);
716 return CMD_SUCCESS;
717}
718
719void
720babeld_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. */
03a38493 748 distribute_list_init(BABEL_NODE);
ca10883e
DS
749}
750
751/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
752
753int
754input_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
761int
762output_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. */
770int
771redistribute_filter(const unsigned char *prefix, unsigned short plen,
772 unsigned int ifindex, int proto)
773{
774 return 0;
775}
776
03a38493
PG
777struct babel *babel_lookup(void)
778{
779 return babel_routing_process;
780}