]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babeld.c
Merge branch 'master' of https://github.com/dwalton76/frr into bgpd-ipv4-plus-label...
[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
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
47 static int babel_init_routing_process(struct thread *thread);
48 static void babel_get_myid(void);
49 static void babel_initial_noise(void);
50 static int babel_read_protocol (struct thread *thread);
51 static int babel_main_loop(struct thread *thread);
52 static void babel_set_timer(struct timeval *timeout);
53 static void babel_fill_with_next_timeout(struct timeval *tv);
54
55
56 /* Informations relative to the babel running daemon. */
57 static struct babel *babel_routing_process = NULL;
58 static unsigned char *receive_buffer = NULL;
59 static int receive_buffer_size = 0;
60
61 /* timeouts */
62 struct timeval check_neighbours_timeout;
63 static time_t expiry_time;
64 static time_t source_expiry_time;
65
66 /* Babel node structure. */
67 static 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 */
75 static int
76 babel_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;
86 vty_outln (vty, "router babel");
87 if (diversity_kind != DIVERSITY_NONE)
88 {
89 vty_outln (vty, " babel diversity");
90 lines++;
91 }
92 if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
93 {
94 vty_outln (vty, " babel diversity-factor %d",diversity_factor);
95 lines++;
96 }
97 if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
98 {
99 vty_outln (vty, " babel resend-delay %u", resend_delay);
100 lines++;
101 }
102 if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
103 {
104 vty_outln (vty, " babel smoothing-half-life %u",
105 smoothing_half_life);
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++)
112 if (i != zclient->redist_default &&
113 vrf_bitmap_check (zclient->redist[AFI_IP][i], VRF_DEFAULT))
114 {
115 vty_outln (vty, " redistribute %s", zebra_route_string(i));
116 lines++;
117 }
118
119 lines += config_write_distribute (vty);
120
121 return lines;
122 }
123
124
125 static int
126 babel_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
151 fail:
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 */
158 static int
159 babel_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. */
196 static int
197 babel_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}). */
209 static void
210 babel_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 */
263 static void
264 babel_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. */
294 static void
295 babel_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. */
313 static int
314 babel_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
398 static void
399 printIfMin(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
438 static void
439 babel_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) */
481 static void
482 babel_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
491 void
492 schedule_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
503 int
504 resize_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
529 static void
530 babel_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
562 static void
563 babel_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. */
573 static void
574 babel_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
583 static void
584 babel_distribute_update_all_wrapper (struct access_list *notused)
585 {
586 babel_distribute_update_all(NULL);
587 }
588
589
590 /* [Command] */
591 DEFUN_NOSH (router_babel,
592 router_babel_cmd,
593 "router babel",
594 "Enable a routing process\n"
595 "Make Babel instance command\n")
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] */
615 DEFUN (no_router_babel,
616 no_router_babel_cmd,
617 "no router babel",
618 NO_STR
619 "Disable a routing process\n"
620 "Remove Babel instance command\n")
621 {
622 if(babel_routing_process)
623 babel_clean_routing_process();
624 return CMD_SUCCESS;
625 }
626
627 /* [Babel Command] */
628 DEFUN (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] */
639 DEFUN (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] */
651 DEFUN (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
660 factor = strtoul(argv[2]->arg, NULL, 10);
661
662 diversity_factor = factor;
663 return CMD_SUCCESS;
664 }
665
666 /* [Babel Command] */
667 DEFUN (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
676 interval = strtoul(argv[2]->arg, NULL, 10);
677
678 resend_delay = interval;
679 return CMD_SUCCESS;
680 }
681
682 /* [Babel Command] */
683 DEFUN (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
692 seconds = strtoul(argv[2]->arg, NULL, 10);
693
694 change_smoothing_half_life(seconds);
695 return CMD_SUCCESS;
696 }
697
698 void
699 babeld_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
734 int
735 input_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
742 int
743 output_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. */
751 int
752 redistribute_filter(const unsigned char *prefix, unsigned short plen,
753 unsigned int ifindex, int proto)
754 {
755 return 0;
756 }
757