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>