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