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