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