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