File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_neighbor.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>