1/* 2 PIM for Quagga 3 Copyright (C) 2008 Everton da Silva Marques 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; see the file COPYING; if not, write to the 17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 18 MA 02110-1301 USA 19 20 $QuaggaId: $Format:%an, %ai, %h$ $ 21*/ 22 23#include <zebra.h> 24 25#include "log.h" 26#include "prefix.h" 27#include "memory.h" 28 29#include "pimd.h" 30#include "pim_neighbor.h" 31#include "pim_time.h" 32#include "pim_str.h" 33#include "pim_iface.h" 34#include "pim_pim.h" 35#include "pim_upstream.h" 36#include "pim_ifchannel.h" 37 38static void dr_election_by_addr(struct interface *ifp) 39{ 40 struct pim_interface *pim_ifp; 41 struct listnode *node; 42 struct pim_neighbor *neigh; 43 44 pim_ifp = ifp->info; 45 zassert(pim_ifp); 46 47 pim_ifp->pim_dr_addr = pim_ifp->primary_address; 48 49 if (PIM_DEBUG_PIM_TRACE) { 50 zlog_debug("%s: on interface %s", 51 __PRETTY_FUNCTION__, 52 ifp->name); 53 } 54 55 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { 56 if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { 57 pim_ifp->pim_dr_addr = neigh->source_addr; 58 } 59 } 60} 61 62static void dr_election_by_pri(struct interface *ifp) 63{ 64 struct pim_interface *pim_ifp; 65 struct listnode *node; 66 struct pim_neighbor *neigh; 67 uint32_t dr_pri; 68 69 pim_ifp = ifp->info; 70 zassert(pim_ifp); 71 72 pim_ifp->pim_dr_addr = pim_ifp->primary_address; 73 dr_pri = pim_ifp->pim_dr_priority; 74 75 if (PIM_DEBUG_PIM_TRACE) { 76 zlog_debug("%s: dr pri %u on interface %s", 77 __PRETTY_FUNCTION__, 78 dr_pri, ifp->name); 79 } 80 81 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { 82 if (PIM_DEBUG_PIM_TRACE) { 83 zlog_info("%s: neigh pri %u addr %x if dr addr %x", 84 __PRETTY_FUNCTION__, 85 neigh->dr_priority, 86 ntohl(neigh->source_addr.s_addr), 87 ntohl(pim_ifp->pim_dr_addr.s_addr)); 88 } 89 if ( 90 (neigh->dr_priority > dr_pri) || 91 ( 92 (neigh->dr_priority == dr_pri) && 93 (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) 94 ) 95 ) { 96 pim_ifp->pim_dr_addr = neigh->source_addr; 97 dr_pri = neigh->dr_priority; 98 } 99 } 100} 101 102/* 103 RFC 4601: 4.3.2. DR Election 104 105 A router's idea of the current DR on an interface can change when a 106 PIM Hello message is received, when a neighbor times out, or when a 107 router's own DR Priority changes. 108 */ 109void pim_if_dr_election(struct interface *ifp) 110{ 111 struct pim_interface *pim_ifp = ifp->info; 112 struct in_addr old_dr_addr; 113 114 ++pim_ifp->pim_dr_election_count; 115 116 old_dr_addr = pim_ifp->pim_dr_addr; 117 118 if (pim_ifp->pim_dr_num_nondrpri_neighbors) { 119 dr_election_by_addr(ifp); 120 } 121 else { 122 dr_election_by_pri(ifp); 123 } 124 125 /* DR changed ? */ 126 if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { 127 128 /* if (PIM_DEBUG_PIM_EVENTS) */ { 129 char dr_old_str[100]; 130 char dr_new_str[100]; 131 pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str)); 132 pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); 133 zlog_debug("%s: DR was %s now is %s on interface %s", 134 __PRETTY_FUNCTION__, 135 dr_old_str, dr_new_str, ifp->name); 136 } 137 138 pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ 139 ++pim_ifp->pim_dr_election_changes; 140 pim_if_update_join_desired(pim_ifp); 141 pim_if_update_could_assert(ifp); 142 pim_if_update_assert_tracking_desired(ifp); 143 } 144} 145 146static void update_dr_priority(struct pim_neighbor *neigh, 147 pim_hello_options hello_options, 148 uint32_t dr_priority) 149{ 150 pim_hello_options will_set_pri; /* boolean */ 151 pim_hello_options bit_flip; /* boolean */ 152 pim_hello_options pri_change; /* boolean */ 153 154 will_set_pri = PIM_OPTION_IS_SET(hello_options, 155 PIM_OPTION_MASK_DR_PRIORITY); 156 157 bit_flip = 158 ( 159 will_set_pri != 160 PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) 161 ); 162 163 if (bit_flip) { 164 struct pim_interface *pim_ifp = neigh->interface->info; 165 166 /* update num. of neighbors without dr_pri */ 167 168 if (will_set_pri) { 169 --pim_ifp->pim_dr_num_nondrpri_neighbors; 170 } 171 else { 172 ++pim_ifp->pim_dr_num_nondrpri_neighbors; 173 } 174 } 175 176 pri_change = 177 ( 178 bit_flip 179 || 180 (neigh->dr_priority != dr_priority) 181 ); 182 183 if (will_set_pri) { 184 neigh->dr_priority = dr_priority; 185 } 186 else { 187 neigh->dr_priority = 0; /* cosmetic unset */ 188 } 189 190 if (pri_change) { 191 /* 192 RFC 4601: 4.3.2. DR Election 193 194 A router's idea of the current DR on an interface can change when a 195 PIM Hello message is received, when a neighbor times out, or when a 196 router's own DR Priority changes. 197 */ 198 pim_if_dr_election(neigh->interface); // router's own DR Priority changes 199 } 200} 201 202static int on_neighbor_timer(struct thread *t) 203{ 204 struct pim_neighbor *neigh; 205 struct interface *ifp; 206 char msg[100]; 207 208 zassert(t); 209 neigh = THREAD_ARG(t); 210 zassert(neigh); 211 212 ifp = neigh->interface; 213 214 if (PIM_DEBUG_PIM_TRACE) { 215 char src_str[100]; 216 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); 217 zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s", 218 neigh->holdtime, src_str, ifp->name); 219 } 220 221 neigh->t_expire_timer = 0; 222 223 snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); 224 pim_neighbor_delete(ifp, neigh, msg); 225 226 /* 227 RFC 4601: 4.3.2. DR Election 228 229 A router's idea of the current DR on an interface can change when a 230 PIM Hello message is received, when a neighbor times out, or when a 231 router's own DR Priority changes. 232 */ 233 pim_if_dr_election(ifp); // neighbor times out 234 235 return 0; 236} 237 238static void neighbor_timer_off(struct pim_neighbor *neigh) 239{ 240 if (PIM_DEBUG_PIM_TRACE) { 241 if (neigh->t_expire_timer) { 242 char src_str[100]; 243 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); 244 zlog_debug("%s: cancelling timer for neighbor %s on %s", 245 __PRETTY_FUNCTION__, 246 src_str, neigh->interface->name); 247 } 248 } 249 THREAD_OFF(neigh->t_expire_timer); 250 zassert(!neigh->t_expire_timer); 251} 252 253void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) 254{ 255 neigh->holdtime = holdtime; 256 257 neighbor_timer_off(neigh); 258 259 /* 260 0xFFFF is request for no holdtime 261 */ 262 if (neigh->holdtime == 0xFFFF) { 263 return; 264 } 265 266 if (PIM_DEBUG_PIM_TRACE) { 267 char src_str[100]; 268 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); 269 zlog_debug("%s: starting %u sec timer for neighbor %s on %s", 270 __PRETTY_FUNCTION__, 271 neigh->holdtime, src_str, neigh->interface->name); 272 } 273 274 THREAD_TIMER_ON(master, neigh->t_expire_timer, 275 on_neighbor_timer, 276 neigh, neigh->holdtime); 277} 278 279static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, 280 struct in_addr source_addr, 281 pim_hello_options hello_options, 282 uint16_t holdtime, 283 uint16_t propagation_delay, 284 uint16_t override_interval, 285 uint32_t dr_priority, 286 uint32_t generation_id, 287 struct list *addr_list) 288{ 289 struct pim_interface *pim_ifp; 290 struct pim_neighbor *neigh; 291 char src_str[100]; 292 293 zassert(ifp); 294 pim_ifp = ifp->info; 295 zassert(pim_ifp); 296 297 neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); 298 if (!neigh) { 299 zlog_err("%s: PIM XMALLOC(%zu) failure", 300 __PRETTY_FUNCTION__, sizeof(*neigh)); 301 return 0; 302 } 303 304 neigh->creation = pim_time_monotonic_sec(); 305 neigh->source_addr = source_addr; 306 neigh->hello_options = hello_options; 307 neigh->propagation_delay_msec = propagation_delay; 308 neigh->override_interval_msec = override_interval; 309 neigh->dr_priority = dr_priority; 310 neigh->generation_id = generation_id; 311 neigh->prefix_list = addr_list; 312 neigh->t_expire_timer = 0; 313 neigh->interface = ifp; 314 315 pim_neighbor_timer_reset(neigh, holdtime); 316 317 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str)); 318 319 if (PIM_DEBUG_PIM_EVENTS) { 320 zlog_debug("%s: creating PIM neighbor %s on interface %s", 321 __PRETTY_FUNCTION__, 322 src_str, ifp->name); 323 } 324 325 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", 326 src_str, ifp->name); 327 328 if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { 329 pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec; 330 } 331 if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) { 332 pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec; 333 } 334 335 if (!PIM_OPTION_IS_SET(neigh->hello_options, 336 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { 337 /* update num. of neighbors without hello option lan_delay */ 338 ++pim_ifp->pim_number_of_nonlandelay_neighbors; 339 } 340 341 if (!PIM_OPTION_IS_SET(neigh->hello_options, 342 PIM_OPTION_MASK_DR_PRIORITY)) { 343 /* update num. of neighbors without hello option dr_pri */ 344 ++pim_ifp->pim_dr_num_nondrpri_neighbors; 345 } 346 347 /* 348 RFC 4601: 4.3.2. DR Election 349 350 A router's idea of the current DR on an interface can change when a 351 PIM Hello message is received, when a neighbor times out, or when a 352 router's own DR Priority changes. 353 */ 354 pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... 355 356 /* 357 RFC 4601: 4.3.1. Sending Hello Messages 358 359 To allow new or rebooting routers to learn of PIM neighbors quickly, 360 when a Hello message is received from a new neighbor, or a Hello 361 message with a new GenID is received from an existing neighbor, a 362 new Hello message should be sent on this interface after a 363 randomized delay between 0 and Triggered_Hello_Delay. 364 */ 365 pim_hello_restart_triggered(neigh->interface); 366 367 return neigh; 368} 369 370static void delete_prefix_list(struct pim_neighbor *neigh) 371{ 372 if (neigh->prefix_list) { 373 374#ifdef DUMP_PREFIX_LIST 375 struct listnode *p_node; 376 struct prefix *p; 377 char addr_str[10]; 378 int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1; 379 int i = 0; 380 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) { 381 pim_inet4_dump("<addr?>", p->u.prefix4, addr_str, sizeof(addr_str)); 382 zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]", 383 __PRETTY_FUNCTION__, 384 (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p, 385 addr_str, i, list_size); 386 ++i; 387 } 388#endif 389 390 list_delete(neigh->prefix_list); 391 neigh->prefix_list = 0; 392 } 393} 394 395void pim_neighbor_free(struct pim_neighbor *neigh) 396{ 397 zassert(!neigh->t_expire_timer); 398 399 delete_prefix_list(neigh); 400 401 XFREE(MTYPE_PIM_NEIGHBOR, neigh); 402} 403 404struct pim_neighbor *pim_neighbor_find(struct interface *ifp, 405 struct in_addr source_addr) 406{ 407 struct pim_interface *pim_ifp; 408 struct listnode *node; 409 struct pim_neighbor *neigh; 410 411 pim_ifp = ifp->info; 412 zassert(pim_ifp); 413 414 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { 415 if (source_addr.s_addr == neigh->source_addr.s_addr) { 416 return neigh; 417 } 418 } 419 420 return 0; 421} 422 423struct pim_neighbor *pim_neighbor_add(struct interface *ifp, 424 struct in_addr source_addr, 425 pim_hello_options hello_options, 426 uint16_t holdtime, 427 uint16_t propagation_delay, 428 uint16_t override_interval, 429 uint32_t dr_priority, 430 uint32_t generation_id, 431 struct list *addr_list) 432{ 433 struct pim_interface *pim_ifp; 434 struct pim_neighbor *neigh; 435 436 neigh = pim_neighbor_new(ifp, source_addr, 437 hello_options, 438 holdtime, 439 propagation_delay, 440 override_interval, 441 dr_priority, 442 generation_id, 443 addr_list); 444 if (!neigh) { 445 return 0; 446 } 447 448 pim_ifp = ifp->info; 449 zassert(pim_ifp); 450 451 listnode_add(pim_ifp->pim_neighbor_list, neigh); 452 453 return neigh; 454} 455 456static uint16_t 457find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp, 458 struct pim_neighbor *highest_neigh) 459{ 460 struct pim_interface *pim_ifp; 461 struct listnode *neigh_node; 462 struct pim_neighbor *neigh; 463 uint16_t next_highest_delay_msec; 464 465 pim_ifp = ifp->info; 466 zassert(pim_ifp); 467 468 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec; 469 470 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { 471 if (neigh == highest_neigh) 472 continue; 473 if (neigh->propagation_delay_msec > next_highest_delay_msec) 474 next_highest_delay_msec = neigh->propagation_delay_msec; 475 } 476 477 return next_highest_delay_msec; 478} 479 480static uint16_t 481find_neighbors_next_highest_override_interval_msec(struct interface *ifp, 482 struct pim_neighbor *highest_neigh) 483{ 484 struct pim_interface *pim_ifp; 485 struct listnode *neigh_node; 486 struct pim_neighbor *neigh; 487 uint16_t next_highest_interval_msec; 488 489 pim_ifp = ifp->info; 490 zassert(pim_ifp); 491 492 next_highest_interval_msec = pim_ifp->pim_override_interval_msec; 493 494 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { 495 if (neigh == highest_neigh) 496 continue; 497 if (neigh->override_interval_msec > next_highest_interval_msec) 498 next_highest_interval_msec = neigh->override_interval_msec; 499 } 500 501 return next_highest_interval_msec; 502} 503 504void pim_neighbor_delete(struct interface *ifp, 505 struct pim_neighbor *neigh, 506 const char *delete_message) 507{ 508 struct pim_interface *pim_ifp; 509 char src_str[100]; 510 511 pim_ifp = ifp->info; 512 zassert(pim_ifp); 513 514 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str)); 515 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", 516 src_str, ifp->name, delete_message); 517 518 neighbor_timer_off(neigh); 519 520 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr); 521 522 if (!PIM_OPTION_IS_SET(neigh->hello_options, 523 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { 524 /* update num. of neighbors without hello option lan_delay */ 525 526 --pim_ifp->pim_number_of_nonlandelay_neighbors; 527 } 528 529 if (!PIM_OPTION_IS_SET(neigh->hello_options, 530 PIM_OPTION_MASK_DR_PRIORITY)) { 531 /* update num. of neighbors without dr_pri */ 532 533 --pim_ifp->pim_dr_num_nondrpri_neighbors; 534 } 535 536 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec); 537 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec); 538 539 if (pim_if_lan_delay_enabled(ifp)) { 540 541 /* will delete a neighbor with highest propagation delay? */ 542 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) { 543 /* then find the next highest propagation delay */ 544 pim_ifp->pim_neighbors_highest_propagation_delay_msec = 545 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh); 546 } 547 548 /* will delete a neighbor with highest override interval? */ 549 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) { 550 /* then find the next highest propagation delay */ 551 pim_ifp->pim_neighbors_highest_override_interval_msec = 552 find_neighbors_next_highest_override_interval_msec(ifp, neigh); 553 } 554 } 555 556 if (PIM_DEBUG_PIM_TRACE) { 557 zlog_debug("%s: deleting PIM neighbor %s on interface %s", 558 __PRETTY_FUNCTION__, 559 src_str, ifp->name); 560 } 561 562 listnode_delete(pim_ifp->pim_neighbor_list, neigh); 563 564 pim_neighbor_free(neigh); 565} 566 567void pim_neighbor_delete_all(struct interface *ifp, 568 const char *delete_message) 569{ 570 struct pim_interface *pim_ifp; 571 struct listnode *neigh_node; 572 struct listnode *neigh_nextnode; 573 struct pim_neighbor *neigh; 574 575 pim_ifp = ifp->info; 576 zassert(pim_ifp); 577 578 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node, 579 neigh_nextnode, neigh)) { 580 pim_neighbor_delete(ifp, neigh, delete_message); 581 } 582} 583 584struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, 585 struct in_addr addr) 586{ 587 struct listnode *node; 588 struct prefix *p; 589 590 if (!neigh->prefix_list) 591 return 0; 592 593 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { 594 if (p->family == AF_INET) { 595 if (addr.s_addr == p->u.prefix4.s_addr) { 596 return p; 597 } 598 } 599 } 600 601 return 0; 602} 603 604/* 605 RFC 4601: 4.3.4. Maintaining Secondary Address Lists 606 607 All the advertised secondary addresses in received Hello messages 608 must be checked against those previously advertised by all other 609 PIM neighbors on that interface. If there is a conflict and the 610 same secondary address was previously advertised by another 611 neighbor, then only the most recently received mapping MUST be 612 maintained, and an error message SHOULD be logged to the 613 administrator in a rate-limited manner. 614*/ 615static void delete_from_neigh_addr(struct interface *ifp, 616 struct list *addr_list, 617 struct in_addr neigh_addr) 618{ 619 struct listnode *addr_node; 620 struct prefix *addr; 621 struct pim_interface *pim_ifp; 622 623 pim_ifp = ifp->info; 624 zassert(pim_ifp); 625 626 zassert(addr_list); 627 628 /* 629 Scan secondary address list 630 */ 631 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, 632 addr)) { 633 struct listnode *neigh_node; 634 struct pim_neighbor *neigh; 635 636 if (addr->family != AF_INET) 637 continue; 638 639 /* 640 Scan neighbors 641 */ 642 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, 643 neigh)) { 644 { 645 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); 646 if (p) { 647 char addr_str[100]; 648 char this_neigh_str[100]; 649 char other_neigh_str[100]; 650 651 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str)); 652 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str)); 653 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str)); 654 655 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s", 656 addr_str, this_neigh_str, other_neigh_str, ifp->name); 657 658 listnode_delete(neigh->prefix_list, p); 659 prefix_free(p); 660 } 661 } 662 663 } /* scan neighbors */ 664 665 } /* scan addr list */ 666 667} 668 669void pim_neighbor_update(struct pim_neighbor *neigh, 670 pim_hello_options hello_options, 671 uint16_t holdtime, 672 uint32_t dr_priority, 673 struct list *addr_list) 674{ 675 struct pim_interface *pim_ifp = neigh->interface->info; 676 677 /* Received holdtime ? */ 678 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { 679 pim_neighbor_timer_reset(neigh, holdtime); 680 } 681 else { 682 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); 683 } 684 685#ifdef DUMP_PREFIX_LIST 686 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d", 687 __PRETTY_FUNCTION__, 688 (unsigned) neigh->prefix_list, 689 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1, 690 (unsigned) addr_list, 691 addr_list ? (int) listcount(addr_list) : -1); 692#endif 693 694 if (neigh->prefix_list == addr_list) { 695 if (addr_list) { 696 zlog_err("%s: internal error: trying to replace same prefix list=%p", 697 __PRETTY_FUNCTION__, (void *) addr_list); 698 } 699 } 700 else { 701 /* Delete existing secondary address list */ 702 delete_prefix_list(neigh); 703 } 704 705 if (addr_list) { 706 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr); 707 } 708 709 /* Replace secondary address list */ 710 neigh->prefix_list = addr_list; 711 712 update_dr_priority(neigh, 713 hello_options, 714 dr_priority); 715 /* 716 Copy flags 717 */ 718 neigh->hello_options = hello_options; 719} 720