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 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#include "babel_zebra.h" 63 64 65static int babel_init_routing_process(struct thread *thread); 66static void babel_get_myid(void); 67static void babel_initial_noise(void); 68static int babel_read_protocol (struct thread *thread); 69static int babel_main_loop(struct thread *thread); 70static void babel_set_timer(struct timeval *timeout); 71static void babel_fill_with_next_timeout(struct timeval *tv); 72 73 74/* Informations relative to the babel running daemon. */ 75static struct babel *babel_routing_process = NULL; 76static unsigned char *receive_buffer = NULL; 77static int receive_buffer_size = 0; 78 79/* timeouts */ 80struct timeval check_neighbours_timeout; 81static time_t expiry_time; 82static time_t source_expiry_time; 83 84/* Babel node structure. */ 85static 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 */ 93static int 94babel_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 124static int 125babel_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 152fail: 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 */ 159static int 160babel_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. */ 198static int 199babel_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}). */ 211static void 212babel_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 */ 265static void 266babel_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. */ 296static void 297babel_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. */ 315static int 316babel_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 399static void 400printIfMin(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 439static void 440babel_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) */ 482static void 483babel_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. */ 494void 495schedule_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 506int 507resize_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 532static void 533babel_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 590static void 591babel_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. */ 601static void 602babel_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 611static void 612babel_distribute_update_all_wrapper (struct access_list *notused) 613{ 614 babel_distribute_update_all(NULL); 615} 616 617 618/* [Command] */ 619DEFUN (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] */ 644DEFUN (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] */ 658DEFUN (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 673void 674babeld_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 705int 706input_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 713int 714output_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. */ 722int 723redistribute_filter(const unsigned char *prefix, unsigned short plen, 724 unsigned int ifindex, int proto) 725{ 726 return 0; 727} 728 729