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