blob: f42a81b6b4aeca3ee305088d9651a1ff95477904 [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{
Matthieu Boutier69394542012-01-28 10:35:12 +0100176 myseqno = (random() & 0xFFFF);
Paul Jakma57345092011-12-25 17:52:09 +0100177 babel_get_myid();
Matthieu Boutier69394542012-01-28 10:35:12 +0100178 babel_load_state_file();
Paul Jakma57345092011-12-25 17:52:09 +0100179 debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
180 babel_initial_noise();
181 babel_main_loop(thread);/* this function self-add to the t_update thread */
182 return 0;
183}
184
185/* fill "myid" with an unique id (only if myid != {0}). */
186static void
187babel_get_myid(void)
188{
189 struct interface *ifp = NULL;
190 struct listnode *linklist_node = NULL;
191 int rc;
192 int i;
193
194 /* if we already have an id (from state file), we return. */
195 if (memcmp(myid, zeroes, 8) != 0) {
196 return;
197 }
198
199 FOR_ALL_INTERFACES(ifp, linklist_node) {
200 /* ifp->ifindex is not necessarily valid at this point */
201 int ifindex = if_nametoindex(ifp->name);
202 if(ifindex > 0) {
203 unsigned char eui[8];
204 rc = if_eui64(ifp->name, ifindex, eui);
205 if(rc < 0)
206 continue;
207 memcpy(myid, eui, 8);
208 return;
209 }
210 }
211
212 /* We failed to get a global EUI64 from the interfaces we were given.
213 Let's try to find an interface with a MAC address. */
214 for(i = 1; i < 256; i++) {
215 char buf[IF_NAMESIZE], *ifname;
216 unsigned char eui[8];
217 ifname = if_indextoname(i, buf);
218 if(ifname == NULL)
219 continue;
220 rc = if_eui64(ifname, i, eui);
221 if(rc < 0)
222 continue;
223 memcpy(myid, eui, 8);
224 return;
225 }
226
227 zlog_err("Warning: couldn't find router id -- using random value.");
228
229 rc = read_random_bytes(myid, 8);
230 if(rc < 0) {
231 zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
232 exit(1);
233 }
234 /* Clear group and global bits */
235 myid[0] &= ~3;
236}
237
238/* Make some noise so that others notice us, and send retractions in
239 case we were restarted recently */
240static void
241babel_initial_noise(void)
242{
243 struct interface *ifp = NULL;
244 struct listnode *linklist_node = NULL;
245
246 FOR_ALL_INTERFACES(ifp, linklist_node) {
247 if(!if_up(ifp))
248 continue;
249 /* Apply jitter before we send the first message. */
250 usleep(roughly(10000));
251 gettime(&babel_now);
252 send_hello(ifp);
253 send_wildcard_retraction(ifp);
254 }
255
256 FOR_ALL_INTERFACES(ifp, linklist_node) {
257 if(!if_up(ifp))
258 continue;
259 usleep(roughly(10000));
260 gettime(&babel_now);
261 send_hello(ifp);
262 send_wildcard_retraction(ifp);
263 send_self_update(ifp);
264 send_request(ifp, NULL, 0);
265 flushupdates(ifp);
266 flushbuf(ifp);
267 }
268}
269
270/* Delete all the added babel routes, make babeld only speak to zebra. */
271static void
272babel_clean_routing_process()
273{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100274 flush_all_routes();
Paul Jakma57345092011-12-25 17:52:09 +0100275 babel_interface_close_all();
276
277 /* cancel threads */
278 if (babel_routing_process->t_read != NULL) {
279 thread_cancel(babel_routing_process->t_read);
280 }
281 if (babel_routing_process->t_update != NULL) {
282 thread_cancel(babel_routing_process->t_update);
283 }
284
285 XFREE(MTYPE_BABEL, babel_routing_process);
286 babel_routing_process = NULL;
287}
288
289/* Function used with timeout. */
290static int
291babel_main_loop(struct thread *thread)
292{
293 struct timeval tv;
294 struct interface *ifp = NULL;
295 struct listnode *linklist_node = NULL;
296
297 while(1) {
298 gettime(&babel_now);
299
300 /* timeouts --------------------------------------------------------- */
301 /* get the next timeout */
302 babel_fill_with_next_timeout(&tv);
303 /* if there is no timeout, we must wait. */
304 if(timeval_compare(&tv, &babel_now) > 0) {
305 timeval_minus(&tv, &tv, &babel_now);
306 debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
307 tv.tv_sec * 1000 + tv.tv_usec / 1000);
308 /* it happens often to have less than 1 ms, it's bad. */
309 timeval_add_msec(&tv, &tv, 300);
310 babel_set_timer(&tv);
311 return 0;
312 }
313
314 gettime(&babel_now);
315
316 /* update database -------------------------------------------------- */
317 if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
318 int msecs;
319 msecs = check_neighbours();
320 msecs = MAX(msecs, 10);
321 schedule_neighbours_check(msecs, 1);
322 }
323
324 if(babel_now.tv_sec >= expiry_time) {
325 expire_routes();
326 expire_resend();
327 expiry_time = babel_now.tv_sec + roughly(30);
328 }
329
330 if(babel_now.tv_sec >= source_expiry_time) {
331 expire_sources();
332 source_expiry_time = babel_now.tv_sec + roughly(300);
333 }
334
335 FOR_ALL_INTERFACES(ifp, linklist_node) {
336 babel_interface_nfo *babel_ifp = NULL;
337 if(!if_up(ifp))
338 continue;
339 babel_ifp = babel_get_if_nfo(ifp);
340 if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
341 send_hello(ifp);
342 if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
343 send_update(ifp, 0, NULL, 0);
344 if(timeval_compare(&babel_now,
345 &babel_ifp->update_flush_timeout) >= 0)
346 flushupdates(ifp);
347 }
348
349 if(resend_time.tv_sec != 0) {
350 if(timeval_compare(&babel_now, &resend_time) >= 0)
351 do_resend();
352 }
353
354 if(unicast_flush_timeout.tv_sec != 0) {
355 if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
356 flush_unicast(1);
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(babel_ifp->flush_timeout.tv_sec != 0) {
365 if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
366 flushbuf(ifp);
367 }
368 }
369 }
370
371 assert(0); /* this line should never be reach */
372}
373
374static void
375printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
376{
377 static struct timeval curr_tv;
378 static char buffer[200];
379 static const char *curr_tag = NULL;
380
381 switch (cmd) {
382 case 0: /* reset timeval */
383 curr_tv = *tv;
384 if(ifname != NULL) {
385 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
386 curr_tag = buffer;
387 } else {
388 curr_tag = tag;
389 }
390 break;
391 case 1: /* take the min */
392 if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
393 break;
394 }
395 if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
396 tv->tv_usec < curr_tv.tv_usec)) {
397 curr_tv = *tv;
398 if(ifname != NULL) {
399 snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
400 curr_tag = buffer;
401 } else {
402 curr_tag = tag;
403 }
404 }
405 break;
406 case 2: /* print message */
407 debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
408 break;
409 default:
410 break;
411 }
412}
413
414static void
415babel_fill_with_next_timeout(struct timeval *tv)
416{
417#if (defined NO_DEBUG)
418#define printIfMin(a,b,c,d)
419#else
420#define printIfMin(a,b,c,d) \
421 if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
422
423 struct interface *ifp = NULL;
424 struct listnode *linklist_node = NULL;
425
426 *tv = check_neighbours_timeout;
427 printIfMin(tv, 0, "check_neighbours_timeout", NULL);
428 timeval_min_sec(tv, expiry_time);
429 printIfMin(tv, 1, "expiry_time", NULL);
430 timeval_min_sec(tv, source_expiry_time);
431 printIfMin(tv, 1, "source_expiry_time", NULL);
432 timeval_min(tv, &resend_time);
433 printIfMin(tv, 1, "resend_time", NULL);
434 FOR_ALL_INTERFACES(ifp, linklist_node) {
435 babel_interface_nfo *babel_ifp = NULL;
436 if(!if_up(ifp))
437 continue;
438 babel_ifp = babel_get_if_nfo(ifp);
439 timeval_min(tv, &babel_ifp->flush_timeout);
440 printIfMin(tv, 1, "flush_timeout", ifp->name);
441 timeval_min(tv, &babel_ifp->hello_timeout);
442 printIfMin(tv, 1, "hello_timeout", ifp->name);
443 timeval_min(tv, &babel_ifp->update_timeout);
444 printIfMin(tv, 1, "update_timeout", ifp->name);
445 timeval_min(tv, &babel_ifp->update_flush_timeout);
446 printIfMin(tv, 1, "update_flush_timeout",ifp->name);
447 }
448 timeval_min(tv, &unicast_flush_timeout);
449 printIfMin(tv, 1, "unicast_flush_timeout", NULL);
450 printIfMin(tv, 2, NULL, NULL);
451#undef printIfMin
452#endif
453}
454
455/* set the t_update thread of the babel routing process to be launch in
456 'timeout' (approximate at the milisecond) */
457static void
458babel_set_timer(struct timeval *timeout)
459{
460 long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
461 if (babel_routing_process->t_update != NULL) {
462 thread_cancel(babel_routing_process->t_update);
463 }
464 babel_routing_process->t_update =
465 thread_add_timer_msec(master, &babel_main_loop, NULL, msecs);
466}
467
468/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */
469void
470schedule_neighbours_check(int msecs, int override)
471{
472 struct timeval timeout;
473
474 timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2));
475 if(override)
476 check_neighbours_timeout = timeout;
477 else
478 timeval_min(&check_neighbours_timeout, &timeout);
479}
480
481int
482resize_receive_buffer(int size)
483{
484 if(size <= receive_buffer_size)
485 return 0;
486
487 if(receive_buffer == NULL) {
488 receive_buffer = malloc(size);
489 if(receive_buffer == NULL) {
490 zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
491 return -1;
492 }
493 receive_buffer_size = size;
494 } else {
495 unsigned char *new;
496 new = realloc(receive_buffer, size);
497 if(new == NULL) {
498 zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
499 return -1;
500 }
501 receive_buffer = new;
502 receive_buffer_size = size;
503 }
504 return 1;
505}
506
507static void
508babel_distribute_update (struct distribute *dist)
509{
510 struct interface *ifp;
511 babel_interface_nfo *babel_ifp;
512 struct access_list *alist;
513 struct prefix_list *plist;
514
515 if (! dist->ifname)
516 return;
517
518 ifp = if_lookup_by_name (dist->ifname);
519 if (ifp == NULL)
520 return;
521
522 babel_ifp = babel_get_if_nfo(ifp);
523
524 if (dist->list[DISTRIBUTE_IN]) {
525 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
526 if (alist)
527 babel_ifp->list[BABEL_FILTER_IN] = alist;
528 else
529 babel_ifp->list[BABEL_FILTER_IN] = NULL;
530 } else {
531 babel_ifp->list[BABEL_FILTER_IN] = NULL;
532 }
533
534 if (dist->list[DISTRIBUTE_OUT]) {
535 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
536 if (alist)
537 babel_ifp->list[BABEL_FILTER_OUT] = alist;
538 else
539 babel_ifp->list[BABEL_FILTER_OUT] = NULL;
540 } else {
541 babel_ifp->list[BABEL_FILTER_OUT] = NULL;
542 }
543
544 if (dist->prefix[DISTRIBUTE_IN]) {
545 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
546 if (plist)
547 babel_ifp->prefix[BABEL_FILTER_IN] = plist;
548 else
549 babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
550 } else {
551 babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
552 }
553
554 if (dist->prefix[DISTRIBUTE_OUT]) {
555 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
556 if (plist)
557 babel_ifp->prefix[BABEL_FILTER_OUT] = plist;
558 else
559 babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
560 } else {
561 babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
562 }
563}
564
Denis Ovsienko3dbda0c2012-01-08 16:52:36 +0400565static void
Paul Jakma57345092011-12-25 17:52:09 +0100566babel_distribute_update_interface (struct interface *ifp)
567{
568 struct distribute *dist;
569
570 dist = distribute_lookup (ifp->name);
571 if (dist)
572 babel_distribute_update (dist);
573}
574
575/* Update all interface's distribute list. */
576static void
577babel_distribute_update_all (struct prefix_list *notused)
578{
579 struct interface *ifp;
580 struct listnode *node;
581
582 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
583 babel_distribute_update_interface (ifp);
584}
585
586static void
587babel_distribute_update_all_wrapper (struct access_list *notused)
588{
589 babel_distribute_update_all(NULL);
590}
591
592
593/* [Command] */
594DEFUN (router_babel,
595 router_babel_cmd,
596 "router babel",
597 "Enable a routing process\n"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100598 "Make Babel instance command\n"
599 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100600{
601 int ret;
602
603 vty->node = BABEL_NODE;
604
605 if (!babel_routing_process) {
606 ret = babel_create_routing_process ();
607
608 /* Notice to user we couldn't create Babel. */
609 if (ret < 0) {
610 zlog_warn ("can't create Babel");
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100611 return CMD_WARNING;
Paul Jakma57345092011-12-25 17:52:09 +0100612 }
613 }
614
615 return CMD_SUCCESS;
616}
617
618/* [Command] */
619DEFUN (no_router_babel,
620 no_router_babel_cmd,
621 "no router babel",
622 NO_STR
623 "Disable a routing process\n"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100624 "Remove Babel instance command\n"
625 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100626{
627 if(babel_routing_process)
628 babel_clean_routing_process();
629 return CMD_SUCCESS;
630}
631
Paul Jakma57345092011-12-25 17:52:09 +0100632void
633babeld_quagga_init(void)
634{
635
636 install_node(&cmd_babel_node, &babel_config_write);
637
638 install_element(CONFIG_NODE, &router_babel_cmd);
639 install_element(CONFIG_NODE, &no_router_babel_cmd);
640
641 install_default(BABEL_NODE);
642
643 babel_if_init();
644
645 /* Access list install. */
646 access_list_init ();
647 access_list_add_hook (babel_distribute_update_all_wrapper);
648 access_list_delete_hook (babel_distribute_update_all_wrapper);
649
650 /* Prefix list initialize.*/
651 prefix_list_init ();
652 prefix_list_add_hook (babel_distribute_update_all);
653 prefix_list_delete_hook (babel_distribute_update_all);
654
655 /* Distribute list install. */
656 distribute_list_init (BABEL_NODE);
657 distribute_list_add_hook (babel_distribute_update);
658 distribute_list_delete_hook (babel_distribute_update);
659}
660
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100661/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
662
663int
Paul Jakma57345092011-12-25 17:52:09 +0100664input_filter(const unsigned char *id,
665 const unsigned char *prefix, unsigned short plen,
666 const unsigned char *neigh, unsigned int ifindex)
667{
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100668 return babel_filter(0, prefix, plen, ifindex);
Paul Jakma57345092011-12-25 17:52:09 +0100669}
670
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100671int
Paul Jakma57345092011-12-25 17:52:09 +0100672output_filter(const unsigned char *id, const unsigned char *prefix,
673 unsigned short plen, unsigned int ifindex)
674{
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100675 return babel_filter(1, prefix, plen, ifindex);
Paul Jakma57345092011-12-25 17:52:09 +0100676}
677
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100678/* There's no redistribute filter in Quagga -- the zebra daemon does its
679 own filtering. */
680int
Paul Jakma57345092011-12-25 17:52:09 +0100681redistribute_filter(const unsigned char *prefix, unsigned short plen,
682 unsigned int ifindex, int proto)
683{
Juliusz Chroboczek31e2a192012-02-09 14:06:11 +0100684 return 0;
Paul Jakma57345092011-12-25 17:52:09 +0100685}
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100686
687void
688show_babeld_configuration (struct vty *vty)
689{
690 vty_out(vty, "babeld running process %s.%s",
691 babel_routing_process ? "enable" : "disable", VTY_NEWLINE);
692}