Annotation of embedaddon/quagga/pimd/pim_neighbor.c, revision 1.1
1.1 ! misho 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:
! 38: static 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:
! 62: static 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: */
! 109: int 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: return 1;
! 144: }
! 145:
! 146: return 0;
! 147: }
! 148:
! 149: static void update_dr_priority(struct pim_neighbor *neigh,
! 150: pim_hello_options hello_options,
! 151: uint32_t dr_priority)
! 152: {
! 153: pim_hello_options will_set_pri; /* boolean */
! 154: pim_hello_options bit_flip; /* boolean */
! 155: pim_hello_options pri_change; /* boolean */
! 156:
! 157: will_set_pri = PIM_OPTION_IS_SET(hello_options,
! 158: PIM_OPTION_MASK_DR_PRIORITY);
! 159:
! 160: bit_flip =
! 161: (
! 162: will_set_pri !=
! 163: PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)
! 164: );
! 165:
! 166: if (bit_flip) {
! 167: struct pim_interface *pim_ifp = neigh->interface->info;
! 168:
! 169: /* update num. of neighbors without dr_pri */
! 170:
! 171: if (will_set_pri) {
! 172: --pim_ifp->pim_dr_num_nondrpri_neighbors;
! 173: }
! 174: else {
! 175: ++pim_ifp->pim_dr_num_nondrpri_neighbors;
! 176: }
! 177: }
! 178:
! 179: pri_change =
! 180: (
! 181: bit_flip
! 182: ||
! 183: (neigh->dr_priority != dr_priority)
! 184: );
! 185:
! 186: if (will_set_pri) {
! 187: neigh->dr_priority = dr_priority;
! 188: }
! 189: else {
! 190: neigh->dr_priority = 0; /* cosmetic unset */
! 191: }
! 192:
! 193: if (pri_change) {
! 194: /*
! 195: RFC 4601: 4.3.2. DR Election
! 196:
! 197: A router's idea of the current DR on an interface can change when a
! 198: PIM Hello message is received, when a neighbor times out, or when a
! 199: router's own DR Priority changes.
! 200: */
! 201: pim_if_dr_election(neigh->interface); // router's own DR Priority changes
! 202: }
! 203: }
! 204:
! 205: static int on_neighbor_timer(struct thread *t)
! 206: {
! 207: struct pim_neighbor *neigh;
! 208: struct interface *ifp;
! 209: char msg[100];
! 210:
! 211: zassert(t);
! 212: neigh = THREAD_ARG(t);
! 213: zassert(neigh);
! 214:
! 215: ifp = neigh->interface;
! 216:
! 217: if (PIM_DEBUG_PIM_TRACE) {
! 218: char src_str[100];
! 219: pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
! 220: zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
! 221: neigh->holdtime, src_str, ifp->name);
! 222: }
! 223:
! 224: neigh->t_expire_timer = 0;
! 225:
! 226: snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
! 227: pim_neighbor_delete(ifp, neigh, msg);
! 228:
! 229: /*
! 230: RFC 4601: 4.3.2. DR Election
! 231:
! 232: A router's idea of the current DR on an interface can change when a
! 233: PIM Hello message is received, when a neighbor times out, or when a
! 234: router's own DR Priority changes.
! 235: */
! 236: pim_if_dr_election(ifp); // neighbor times out
! 237:
! 238: return 0;
! 239: }
! 240:
! 241: static void neighbor_timer_off(struct pim_neighbor *neigh)
! 242: {
! 243: if (PIM_DEBUG_PIM_TRACE) {
! 244: if (neigh->t_expire_timer) {
! 245: char src_str[100];
! 246: pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
! 247: zlog_debug("%s: cancelling timer for neighbor %s on %s",
! 248: __PRETTY_FUNCTION__,
! 249: src_str, neigh->interface->name);
! 250: }
! 251: }
! 252: THREAD_OFF(neigh->t_expire_timer);
! 253: zassert(!neigh->t_expire_timer);
! 254: }
! 255:
! 256: void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
! 257: {
! 258: neigh->holdtime = holdtime;
! 259:
! 260: neighbor_timer_off(neigh);
! 261:
! 262: /*
! 263: 0xFFFF is request for no holdtime
! 264: */
! 265: if (neigh->holdtime == 0xFFFF) {
! 266: return;
! 267: }
! 268:
! 269: if (PIM_DEBUG_PIM_TRACE) {
! 270: char src_str[100];
! 271: pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
! 272: zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
! 273: __PRETTY_FUNCTION__,
! 274: neigh->holdtime, src_str, neigh->interface->name);
! 275: }
! 276:
! 277: THREAD_TIMER_ON(master, neigh->t_expire_timer,
! 278: on_neighbor_timer,
! 279: neigh, neigh->holdtime);
! 280: }
! 281:
! 282: static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
! 283: struct in_addr source_addr,
! 284: pim_hello_options hello_options,
! 285: uint16_t holdtime,
! 286: uint16_t propagation_delay,
! 287: uint16_t override_interval,
! 288: uint32_t dr_priority,
! 289: uint32_t generation_id,
! 290: struct list *addr_list)
! 291: {
! 292: struct pim_interface *pim_ifp;
! 293: struct pim_neighbor *neigh;
! 294: char src_str[100];
! 295:
! 296: zassert(ifp);
! 297: pim_ifp = ifp->info;
! 298: zassert(pim_ifp);
! 299:
! 300: neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
! 301: if (!neigh) {
! 302: zlog_err("%s: PIM XMALLOC(%zu) failure",
! 303: __PRETTY_FUNCTION__, sizeof(*neigh));
! 304: return 0;
! 305: }
! 306:
! 307: neigh->creation = pim_time_monotonic_sec();
! 308: neigh->source_addr = source_addr;
! 309: neigh->hello_options = hello_options;
! 310: neigh->propagation_delay_msec = propagation_delay;
! 311: neigh->override_interval_msec = override_interval;
! 312: neigh->dr_priority = dr_priority;
! 313: neigh->generation_id = generation_id;
! 314: neigh->prefix_list = addr_list;
! 315: neigh->t_expire_timer = 0;
! 316: neigh->interface = ifp;
! 317:
! 318: pim_neighbor_timer_reset(neigh, holdtime);
! 319:
! 320: pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
! 321:
! 322: if (PIM_DEBUG_PIM_EVENTS) {
! 323: zlog_debug("%s: creating PIM neighbor %s on interface %s",
! 324: __PRETTY_FUNCTION__,
! 325: src_str, ifp->name);
! 326: }
! 327:
! 328: zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
! 329: src_str, ifp->name);
! 330:
! 331: if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
! 332: pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec;
! 333: }
! 334: if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) {
! 335: pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec;
! 336: }
! 337:
! 338: if (!PIM_OPTION_IS_SET(neigh->hello_options,
! 339: PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
! 340: /* update num. of neighbors without hello option lan_delay */
! 341: ++pim_ifp->pim_number_of_nonlandelay_neighbors;
! 342: }
! 343:
! 344: if (!PIM_OPTION_IS_SET(neigh->hello_options,
! 345: PIM_OPTION_MASK_DR_PRIORITY)) {
! 346: /* update num. of neighbors without hello option dr_pri */
! 347: ++pim_ifp->pim_dr_num_nondrpri_neighbors;
! 348: }
! 349:
! 350: return neigh;
! 351: }
! 352:
! 353: static void delete_prefix_list(struct pim_neighbor *neigh)
! 354: {
! 355: if (neigh->prefix_list) {
! 356:
! 357: #ifdef DUMP_PREFIX_LIST
! 358: struct listnode *p_node;
! 359: struct prefix *p;
! 360: char addr_str[10];
! 361: int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1;
! 362: int i = 0;
! 363: for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) {
! 364: pim_inet4_dump("<addr?>", p->u.prefix4, addr_str, sizeof(addr_str));
! 365: zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
! 366: __PRETTY_FUNCTION__,
! 367: (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p,
! 368: addr_str, i, list_size);
! 369: ++i;
! 370: }
! 371: #endif
! 372:
! 373: list_delete(neigh->prefix_list);
! 374: neigh->prefix_list = 0;
! 375: }
! 376: }
! 377:
! 378: void pim_neighbor_free(struct pim_neighbor *neigh)
! 379: {
! 380: zassert(!neigh->t_expire_timer);
! 381:
! 382: delete_prefix_list(neigh);
! 383:
! 384: XFREE(MTYPE_PIM_NEIGHBOR, neigh);
! 385: }
! 386:
! 387: struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
! 388: struct in_addr source_addr)
! 389: {
! 390: struct pim_interface *pim_ifp;
! 391: struct listnode *node;
! 392: struct pim_neighbor *neigh;
! 393:
! 394: pim_ifp = ifp->info;
! 395: zassert(pim_ifp);
! 396:
! 397: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
! 398: if (source_addr.s_addr == neigh->source_addr.s_addr) {
! 399: return neigh;
! 400: }
! 401: }
! 402:
! 403: return 0;
! 404: }
! 405:
! 406: struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
! 407: struct in_addr source_addr,
! 408: pim_hello_options hello_options,
! 409: uint16_t holdtime,
! 410: uint16_t propagation_delay,
! 411: uint16_t override_interval,
! 412: uint32_t dr_priority,
! 413: uint32_t generation_id,
! 414: struct list *addr_list)
! 415: {
! 416: struct pim_interface *pim_ifp;
! 417: struct pim_neighbor *neigh;
! 418:
! 419: neigh = pim_neighbor_new(ifp, source_addr,
! 420: hello_options,
! 421: holdtime,
! 422: propagation_delay,
! 423: override_interval,
! 424: dr_priority,
! 425: generation_id,
! 426: addr_list);
! 427: if (!neigh) {
! 428: return 0;
! 429: }
! 430:
! 431: pim_ifp = ifp->info;
! 432: zassert(pim_ifp);
! 433:
! 434: listnode_add(pim_ifp->pim_neighbor_list, neigh);
! 435:
! 436: /*
! 437: RFC 4601: 4.3.2. DR Election
! 438:
! 439: A router's idea of the current DR on an interface can change when a
! 440: PIM Hello message is received, when a neighbor times out, or when a
! 441: router's own DR Priority changes.
! 442: */
! 443: pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election...
! 444:
! 445: /*
! 446: RFC 4601: 4.3.1. Sending Hello Messages
! 447:
! 448: To allow new or rebooting routers to learn of PIM neighbors quickly,
! 449: when a Hello message is received from a new neighbor, or a Hello
! 450: message with a new GenID is received from an existing neighbor, a
! 451: new Hello message should be sent on this interface after a
! 452: randomized delay between 0 and Triggered_Hello_Delay.
! 453: */
! 454: pim_hello_restart_triggered(neigh->interface);
! 455:
! 456: return neigh;
! 457: }
! 458:
! 459: static uint16_t
! 460: find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
! 461: struct pim_neighbor *highest_neigh)
! 462: {
! 463: struct pim_interface *pim_ifp;
! 464: struct listnode *neigh_node;
! 465: struct pim_neighbor *neigh;
! 466: uint16_t next_highest_delay_msec;
! 467:
! 468: pim_ifp = ifp->info;
! 469: zassert(pim_ifp);
! 470:
! 471: next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
! 472:
! 473: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
! 474: if (neigh == highest_neigh)
! 475: continue;
! 476: if (neigh->propagation_delay_msec > next_highest_delay_msec)
! 477: next_highest_delay_msec = neigh->propagation_delay_msec;
! 478: }
! 479:
! 480: return next_highest_delay_msec;
! 481: }
! 482:
! 483: static uint16_t
! 484: find_neighbors_next_highest_override_interval_msec(struct interface *ifp,
! 485: struct pim_neighbor *highest_neigh)
! 486: {
! 487: struct pim_interface *pim_ifp;
! 488: struct listnode *neigh_node;
! 489: struct pim_neighbor *neigh;
! 490: uint16_t next_highest_interval_msec;
! 491:
! 492: pim_ifp = ifp->info;
! 493: zassert(pim_ifp);
! 494:
! 495: next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
! 496:
! 497: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
! 498: if (neigh == highest_neigh)
! 499: continue;
! 500: if (neigh->override_interval_msec > next_highest_interval_msec)
! 501: next_highest_interval_msec = neigh->override_interval_msec;
! 502: }
! 503:
! 504: return next_highest_interval_msec;
! 505: }
! 506:
! 507: void pim_neighbor_delete(struct interface *ifp,
! 508: struct pim_neighbor *neigh,
! 509: const char *delete_message)
! 510: {
! 511: struct pim_interface *pim_ifp;
! 512: char src_str[100];
! 513:
! 514: pim_ifp = ifp->info;
! 515: zassert(pim_ifp);
! 516:
! 517: pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
! 518: zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
! 519: src_str, ifp->name, delete_message);
! 520:
! 521: neighbor_timer_off(neigh);
! 522:
! 523: pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
! 524:
! 525: if (!PIM_OPTION_IS_SET(neigh->hello_options,
! 526: PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
! 527: /* update num. of neighbors without hello option lan_delay */
! 528:
! 529: --pim_ifp->pim_number_of_nonlandelay_neighbors;
! 530: }
! 531:
! 532: if (!PIM_OPTION_IS_SET(neigh->hello_options,
! 533: PIM_OPTION_MASK_DR_PRIORITY)) {
! 534: /* update num. of neighbors without dr_pri */
! 535:
! 536: --pim_ifp->pim_dr_num_nondrpri_neighbors;
! 537: }
! 538:
! 539: zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
! 540: zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
! 541:
! 542: if (pim_if_lan_delay_enabled(ifp)) {
! 543:
! 544: /* will delete a neighbor with highest propagation delay? */
! 545: if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
! 546: /* then find the next highest propagation delay */
! 547: pim_ifp->pim_neighbors_highest_propagation_delay_msec =
! 548: find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
! 549: }
! 550:
! 551: /* will delete a neighbor with highest override interval? */
! 552: if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
! 553: /* then find the next highest propagation delay */
! 554: pim_ifp->pim_neighbors_highest_override_interval_msec =
! 555: find_neighbors_next_highest_override_interval_msec(ifp, neigh);
! 556: }
! 557: }
! 558:
! 559: if (PIM_DEBUG_PIM_TRACE) {
! 560: zlog_debug("%s: deleting PIM neighbor %s on interface %s",
! 561: __PRETTY_FUNCTION__,
! 562: src_str, ifp->name);
! 563: }
! 564:
! 565: listnode_delete(pim_ifp->pim_neighbor_list, neigh);
! 566:
! 567: pim_neighbor_free(neigh);
! 568: }
! 569:
! 570: void pim_neighbor_delete_all(struct interface *ifp,
! 571: const char *delete_message)
! 572: {
! 573: struct pim_interface *pim_ifp;
! 574: struct listnode *neigh_node;
! 575: struct listnode *neigh_nextnode;
! 576: struct pim_neighbor *neigh;
! 577:
! 578: pim_ifp = ifp->info;
! 579: zassert(pim_ifp);
! 580:
! 581: for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
! 582: neigh_nextnode, neigh)) {
! 583: pim_neighbor_delete(ifp, neigh, delete_message);
! 584: }
! 585: }
! 586:
! 587: struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
! 588: struct in_addr addr)
! 589: {
! 590: struct listnode *node;
! 591: struct prefix *p;
! 592:
! 593: if (!neigh->prefix_list)
! 594: return 0;
! 595:
! 596: for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
! 597: if (p->family == AF_INET) {
! 598: if (addr.s_addr == p->u.prefix4.s_addr) {
! 599: return p;
! 600: }
! 601: }
! 602: }
! 603:
! 604: return 0;
! 605: }
! 606:
! 607: /*
! 608: RFC 4601: 4.3.4. Maintaining Secondary Address Lists
! 609:
! 610: All the advertised secondary addresses in received Hello messages
! 611: must be checked against those previously advertised by all other
! 612: PIM neighbors on that interface. If there is a conflict and the
! 613: same secondary address was previously advertised by another
! 614: neighbor, then only the most recently received mapping MUST be
! 615: maintained, and an error message SHOULD be logged to the
! 616: administrator in a rate-limited manner.
! 617: */
! 618: static void delete_from_neigh_addr(struct interface *ifp,
! 619: struct list *addr_list,
! 620: struct in_addr neigh_addr)
! 621: {
! 622: struct listnode *addr_node;
! 623: struct prefix *addr;
! 624: struct pim_interface *pim_ifp;
! 625:
! 626: pim_ifp = ifp->info;
! 627: zassert(pim_ifp);
! 628:
! 629: zassert(addr_list);
! 630:
! 631: /*
! 632: Scan secondary address list
! 633: */
! 634: for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
! 635: addr)) {
! 636: struct listnode *neigh_node;
! 637: struct pim_neighbor *neigh;
! 638:
! 639: if (addr->family != AF_INET)
! 640: continue;
! 641:
! 642: /*
! 643: Scan neighbors
! 644: */
! 645: for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
! 646: neigh)) {
! 647: {
! 648: struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
! 649: if (p) {
! 650: char addr_str[100];
! 651: char this_neigh_str[100];
! 652: char other_neigh_str[100];
! 653:
! 654: pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
! 655: pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
! 656: pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
! 657:
! 658: zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
! 659: addr_str, this_neigh_str, other_neigh_str, ifp->name);
! 660:
! 661: listnode_delete(neigh->prefix_list, p);
! 662: prefix_free(p);
! 663: }
! 664: }
! 665:
! 666: } /* scan neighbors */
! 667:
! 668: } /* scan addr list */
! 669:
! 670: }
! 671:
! 672: void pim_neighbor_update(struct pim_neighbor *neigh,
! 673: pim_hello_options hello_options,
! 674: uint16_t holdtime,
! 675: uint32_t dr_priority,
! 676: struct list *addr_list)
! 677: {
! 678: struct pim_interface *pim_ifp = neigh->interface->info;
! 679:
! 680: /* Received holdtime ? */
! 681: if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
! 682: pim_neighbor_timer_reset(neigh, holdtime);
! 683: }
! 684: else {
! 685: pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
! 686: }
! 687:
! 688: #ifdef DUMP_PREFIX_LIST
! 689: zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
! 690: __PRETTY_FUNCTION__,
! 691: (unsigned) neigh->prefix_list,
! 692: neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
! 693: (unsigned) addr_list,
! 694: addr_list ? (int) listcount(addr_list) : -1);
! 695: #endif
! 696:
! 697: if (neigh->prefix_list == addr_list) {
! 698: if (addr_list) {
! 699: zlog_err("%s: internal error: trying to replace same prefix list=%p",
! 700: __PRETTY_FUNCTION__, (void *) addr_list);
! 701: }
! 702: }
! 703: else {
! 704: /* Delete existing secondary address list */
! 705: delete_prefix_list(neigh);
! 706: }
! 707:
! 708: if (addr_list) {
! 709: delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
! 710: }
! 711:
! 712: /* Replace secondary address list */
! 713: neigh->prefix_list = addr_list;
! 714:
! 715: update_dr_priority(neigh,
! 716: hello_options,
! 717: dr_priority);
! 718: /*
! 719: Copy flags
! 720: */
! 721: neigh->hello_options = hello_options;
! 722: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>