File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_upstream.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 (8 years, 7 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 "zebra/rib.h"
   26: 
   27: #include "log.h"
   28: #include "zclient.h"
   29: #include "memory.h"
   30: #include "thread.h"
   31: #include "linklist.h"
   32: 
   33: #include "pimd.h"
   34: #include "pim_pim.h"
   35: #include "pim_str.h"
   36: #include "pim_time.h"
   37: #include "pim_iface.h"
   38: #include "pim_join.h"
   39: #include "pim_zlookup.h"
   40: #include "pim_upstream.h"
   41: #include "pim_ifchannel.h"
   42: #include "pim_neighbor.h"
   43: #include "pim_rpf.h"
   44: #include "pim_zebra.h"
   45: #include "pim_oil.h"
   46: #include "pim_macro.h"
   47: 
   48: static void join_timer_start(struct pim_upstream *up);
   49: static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
   50: 
   51: void pim_upstream_free(struct pim_upstream *up)
   52: {
   53:   XFREE(MTYPE_PIM_UPSTREAM, up);
   54: }
   55: 
   56: static void upstream_channel_oil_detach(struct pim_upstream *up)
   57: {
   58:   if (up->channel_oil) {
   59:     pim_channel_oil_del(up->channel_oil);
   60:     up->channel_oil = 0;
   61:   }
   62: }
   63: 
   64: void pim_upstream_delete(struct pim_upstream *up)
   65: {
   66:   THREAD_OFF(up->t_join_timer);
   67: 
   68:   upstream_channel_oil_detach(up);
   69: 
   70:   /*
   71:     notice that listnode_delete() can't be moved
   72:     into pim_upstream_free() because the later is
   73:     called by list_delete_all_node()
   74:   */
   75:   listnode_delete(qpim_upstream_list, up);
   76: 
   77:   pim_upstream_free(up);
   78: }
   79: 
   80: static void send_join(struct pim_upstream *up)
   81: {
   82:   zassert(up->join_state == PIM_UPSTREAM_JOINED);
   83: 
   84:   
   85:   if (PIM_DEBUG_PIM_TRACE) {
   86:     if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
   87:       char src_str[100];
   88:       char grp_str[100];
   89:       char rpf_str[100];
   90:       pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
   91:       pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
   92:       pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
   93:       zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s",
   94: 		__PRETTY_FUNCTION__,
   95: 		src_str, grp_str, rpf_str);
   96:       /* warning only */
   97:     }
   98:   }
   99:   
  100:   /* send Join(S,G) to the current upstream neighbor */
  101:   pim_joinprune_send(up->rpf.source_nexthop.interface,
  102:   		     up->rpf.rpf_addr,
  103: 		     up->source_addr,
  104: 		     up->group_addr,
  105: 		     1 /* join */);
  106: }
  107: 
  108: static int on_join_timer(struct thread *t)
  109: {
  110:   struct pim_upstream *up;
  111: 
  112:   zassert(t);
  113:   up = THREAD_ARG(t);
  114:   zassert(up);
  115: 
  116:   send_join(up);
  117: 
  118:   up->t_join_timer = 0;
  119:   join_timer_start(up);
  120: 
  121:   return 0;
  122: }
  123: 
  124: static void join_timer_start(struct pim_upstream *up)
  125: {
  126:   if (PIM_DEBUG_PIM_EVENTS) {
  127:     char src_str[100];
  128:     char grp_str[100];
  129:     pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  130:     pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  131:     zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)",
  132: 	       __PRETTY_FUNCTION__,
  133: 	       qpim_t_periodic,
  134: 	       src_str, grp_str);
  135:   }
  136: 
  137:   zassert(!up->t_join_timer);
  138: 
  139:   THREAD_TIMER_ON(master, up->t_join_timer,
  140: 		  on_join_timer,
  141: 		  up, qpim_t_periodic);
  142: }
  143: 
  144: void pim_upstream_join_timer_restart(struct pim_upstream *up)
  145: {
  146:   THREAD_OFF(up->t_join_timer);
  147:   join_timer_start(up);
  148: }
  149: 
  150: static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
  151: 						 int interval_msec)
  152: {
  153:   if (PIM_DEBUG_PIM_EVENTS) {
  154:     char src_str[100];
  155:     char grp_str[100];
  156:     pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  157:     pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  158:     zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)",
  159: 	       __PRETTY_FUNCTION__,
  160: 	       interval_msec,
  161: 	       src_str, grp_str);
  162:   }
  163: 
  164:   THREAD_OFF(up->t_join_timer);
  165:   THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
  166: 		       on_join_timer,
  167: 		       up, interval_msec);
  168: }
  169: 
  170: void pim_upstream_join_suppress(struct pim_upstream *up,
  171: 				struct in_addr rpf_addr,
  172: 				int holdtime)
  173: {
  174:   long t_joinsuppress_msec;
  175:   long join_timer_remain_msec;
  176: 
  177:   t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
  178: 			    1000 * holdtime);
  179: 
  180:   join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
  181: 
  182:   if (PIM_DEBUG_PIM_TRACE) {
  183:     char src_str[100];
  184:     char grp_str[100];
  185:     char rpf_str[100];
  186:     pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  187:     pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  188:     pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
  189:     zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
  190: 	       __FILE__, __PRETTY_FUNCTION__, 
  191: 	       src_str, grp_str,
  192: 	       rpf_str,
  193: 	       join_timer_remain_msec, t_joinsuppress_msec);
  194:   }
  195: 
  196:   if (join_timer_remain_msec < t_joinsuppress_msec) {
  197:     if (PIM_DEBUG_PIM_TRACE) {
  198:       char src_str[100];
  199:       char grp_str[100];
  200:       pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  201:       pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  202:       zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec",
  203: 		 __FILE__, __PRETTY_FUNCTION__, 
  204: 		 src_str, grp_str, t_joinsuppress_msec);
  205:     }
  206: 
  207:     pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
  208:   }
  209: }
  210: 
  211: void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
  212: 						    struct pim_upstream *up,
  213: 						    struct in_addr rpf_addr)
  214: {
  215:   long join_timer_remain_msec;
  216:   int t_override_msec;
  217: 
  218:   join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
  219:   t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
  220: 
  221:   if (PIM_DEBUG_PIM_TRACE) {
  222:     char src_str[100];
  223:     char grp_str[100];
  224:     char rpf_str[100];
  225:     pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  226:     pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  227:     pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
  228:     zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec",
  229: 	       debug_label,
  230: 	       src_str, grp_str, rpf_str,
  231: 	       join_timer_remain_msec, t_override_msec);
  232:   }
  233:     
  234:   if (join_timer_remain_msec > t_override_msec) {
  235:     if (PIM_DEBUG_PIM_TRACE) {
  236:       char src_str[100];
  237:       char grp_str[100];
  238:       pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  239:       pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  240:       zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec",
  241: 		 debug_label,
  242: 		 src_str, grp_str,
  243: 		 t_override_msec);
  244:     }
  245: 
  246:     pim_upstream_join_timer_restart_msec(up, t_override_msec);
  247:   }
  248: }
  249: 
  250: static void forward_on(struct pim_upstream *up)
  251: {
  252:   struct listnode      *ifnode;
  253:   struct listnode      *ifnextnode;
  254:   struct listnode      *chnode;
  255:   struct listnode      *chnextnode;
  256:   struct interface     *ifp;
  257:   struct pim_interface *pim_ifp;
  258:   struct pim_ifchannel *ch;
  259: 
  260:   /* scan all interfaces */
  261:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  262:     pim_ifp = ifp->info;
  263:     if (!pim_ifp)
  264:       continue;
  265: 
  266:     /* scan per-interface (S,G) state */
  267:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  268: 
  269:       if (ch->upstream != up)
  270: 	continue;
  271: 
  272:       if (pim_macro_chisin_oiflist(ch))
  273: 	pim_forward_start(ch);
  274: 
  275:     } /* scan iface channel list */
  276:   } /* scan iflist */
  277: }
  278: 
  279: static void forward_off(struct pim_upstream *up)
  280: {
  281:   struct listnode      *ifnode;
  282:   struct listnode      *ifnextnode;
  283:   struct listnode      *chnode;
  284:   struct listnode      *chnextnode;
  285:   struct interface     *ifp;
  286:   struct pim_interface *pim_ifp;
  287:   struct pim_ifchannel *ch;
  288: 
  289:   /* scan all interfaces */
  290:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  291:     pim_ifp = ifp->info;
  292:     if (!pim_ifp)
  293:       continue;
  294: 
  295:     /* scan per-interface (S,G) state */
  296:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  297: 
  298:       if (ch->upstream != up)
  299: 	continue;
  300: 
  301:       pim_forward_stop(ch);
  302: 
  303:     } /* scan iface channel list */
  304:   } /* scan iflist */
  305: }
  306: 
  307: static void pim_upstream_switch(struct pim_upstream *up,
  308: 				enum pim_upstream_state new_state)
  309: {
  310:   enum pim_upstream_state old_state = up->join_state;
  311: 
  312:   zassert(old_state != new_state);
  313:   
  314:   up->join_state       = new_state;
  315:   up->state_transition = pim_time_monotonic_sec();
  316: 
  317:   if (PIM_DEBUG_PIM_EVENTS) {
  318:     char src_str[100];
  319:     char grp_str[100];
  320:     pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  321:     pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  322:     zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
  323: 	       __PRETTY_FUNCTION__,
  324: 	       ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
  325: 	       src_str, grp_str);
  326:   }
  327: 
  328:   pim_upstream_update_assert_tracking_desired(up);
  329: 
  330:   if (new_state == PIM_UPSTREAM_JOINED) {
  331:     forward_on(up);
  332:     send_join(up);
  333:     join_timer_start(up);
  334:   }
  335:   else {
  336:     forward_off(up);
  337:     pim_joinprune_send(up->rpf.source_nexthop.interface,
  338: 		       up->rpf.rpf_addr,
  339: 		       up->source_addr,
  340: 		       up->group_addr,
  341: 		       0 /* prune */);
  342:     zassert(up->t_join_timer);
  343:     THREAD_OFF(up->t_join_timer);
  344:   }
  345: 
  346: }
  347: 
  348: static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
  349: 					     struct in_addr group_addr)
  350: {
  351:   struct pim_upstream *up;
  352:   enum pim_rpf_result rpf_result;
  353: 
  354:   up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
  355:   if (!up) {
  356:     zlog_err("%s: PIM XMALLOC(%zu) failure",
  357: 	     __PRETTY_FUNCTION__, sizeof(*up));
  358:     return 0;
  359:   }
  360:   
  361:   up->source_addr                = source_addr;
  362:   up->group_addr                 = group_addr;
  363:   up->flags                      = 0;
  364:   up->ref_count                  = 1;
  365:   up->t_join_timer               = 0;
  366:   up->join_state                 = 0;
  367:   up->state_transition           = pim_time_monotonic_sec();
  368:   up->channel_oil                = 0;
  369: 
  370:   up->rpf.source_nexthop.interface                = 0;
  371:   up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
  372:   up->rpf.source_nexthop.mrib_metric_preference   = qpim_infinite_assert_metric.metric_preference;
  373:   up->rpf.source_nexthop.mrib_route_metric        = qpim_infinite_assert_metric.route_metric;
  374:   up->rpf.rpf_addr.s_addr                         = PIM_NET_INADDR_ANY;
  375: 
  376:   rpf_result = pim_rpf_update(up, 0);
  377:   if (rpf_result == PIM_RPF_FAILURE) {
  378:     XFREE(MTYPE_PIM_UPSTREAM, up);
  379:     return NULL;
  380:   }
  381: 
  382:   listnode_add(qpim_upstream_list, up);
  383: 
  384:   return up;
  385: }
  386: 
  387: struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
  388: 				       struct in_addr group_addr)
  389: {
  390:   struct listnode     *up_node;
  391:   struct pim_upstream *up;
  392: 
  393:   for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
  394:     if (
  395: 	(source_addr.s_addr == up->source_addr.s_addr) &&
  396: 	(group_addr.s_addr == up->group_addr.s_addr)
  397: 	) {
  398:       return up;
  399:     }
  400:   }
  401: 
  402:   return 0;
  403: }
  404: 
  405: struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
  406: 				      struct in_addr group_addr)
  407: {
  408:   struct pim_upstream *up;
  409: 
  410:   up = pim_upstream_find(source_addr, group_addr);
  411:   if (up) {
  412:     ++up->ref_count;
  413:   }
  414:   else {
  415:     up = pim_upstream_new(source_addr, group_addr);
  416:   }
  417: 
  418:   return up;
  419: }
  420: 
  421: void pim_upstream_del(struct pim_upstream *up)
  422: {
  423:   --up->ref_count;
  424: 
  425:   if (up->ref_count < 1) {
  426:     pim_upstream_delete(up);
  427:   }
  428: }
  429: 
  430: /*
  431:   Evaluate JoinDesired(S,G):
  432: 
  433:   JoinDesired(S,G) is true if there is a downstream (S,G) interface I
  434:   in the set:
  435: 
  436:   inherited_olist(S,G) =
  437:   joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
  438: 
  439:   JoinDesired(S,G) may be affected by changes in the following:
  440: 
  441:   pim_ifp->primary_address
  442:   pim_ifp->pim_dr_addr
  443:   ch->ifassert_winner_metric
  444:   ch->ifassert_winner
  445:   ch->local_ifmembership 
  446:   ch->ifjoin_state
  447:   ch->upstream->rpf.source_nexthop.mrib_metric_preference
  448:   ch->upstream->rpf.source_nexthop.mrib_route_metric
  449:   ch->upstream->rpf.source_nexthop.interface
  450: 
  451:   See also pim_upstream_update_join_desired() below.
  452:  */
  453: int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
  454: {
  455:   struct listnode      *ifnode;
  456:   struct listnode      *ifnextnode;
  457:   struct listnode      *chnode;
  458:   struct listnode      *chnextnode;
  459:   struct interface     *ifp;
  460:   struct pim_interface *pim_ifp;
  461:   struct pim_ifchannel *ch;
  462: 
  463:   /* scan all interfaces */
  464:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  465:     pim_ifp = ifp->info;
  466:     if (!pim_ifp)
  467:       continue;
  468: 
  469:     /* scan per-interface (S,G) state */
  470:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  471:       if (ch->upstream != up)
  472: 	continue;
  473: 
  474:       if (pim_macro_ch_lost_assert(ch))
  475: 	continue; /* keep searching */
  476: 
  477:       if (pim_macro_chisin_joins_or_include(ch))
  478: 	return 1; /* true */
  479:     } /* scan iface channel list */
  480:   } /* scan iflist */
  481: 
  482:   return 0; /* false */
  483: }
  484: 
  485: /*
  486:   See also pim_upstream_evaluate_join_desired() above.
  487: */
  488: void pim_upstream_update_join_desired(struct pim_upstream *up)
  489: {
  490:   int was_join_desired; /* boolean */
  491:   int is_join_desired; /* boolean */
  492: 
  493:   was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
  494: 
  495:   is_join_desired = pim_upstream_evaluate_join_desired(up);
  496:   if (is_join_desired)
  497:     PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
  498:   else
  499:     PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
  500: 
  501:   /* switched from false to true */
  502:   if (is_join_desired && !was_join_desired) {
  503:     zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
  504:     pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
  505:     return;
  506:   }
  507:       
  508:   /* switched from true to false */
  509:   if (!is_join_desired && was_join_desired) {
  510:     zassert(up->join_state == PIM_UPSTREAM_JOINED);
  511:     pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
  512:     return;
  513:   }
  514: }
  515: 
  516: /*
  517:   RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
  518:   Transitions from Joined State
  519:   RPF'(S,G) GenID changes
  520: 
  521:   The upstream (S,G) state machine remains in Joined state.  If the
  522:   Join Timer is set to expire in more than t_override seconds, reset
  523:   it so that it expires after t_override seconds.
  524: */
  525: void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
  526: {
  527:   struct listnode     *up_node;
  528:   struct listnode     *up_nextnode;
  529:   struct pim_upstream *up;
  530: 
  531:   /*
  532:     Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
  533:   */
  534:   for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
  535: 
  536:     if (PIM_DEBUG_PIM_TRACE) {
  537:       char neigh_str[100];
  538:       char src_str[100];
  539:       char grp_str[100];
  540:       char rpf_addr_str[100];
  541:       pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
  542:       pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
  543:       pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
  544:       pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
  545:       zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
  546: 		 __PRETTY_FUNCTION__,
  547: 		 neigh_str, src_str, grp_str,
  548: 		 up->join_state == PIM_UPSTREAM_JOINED,
  549: 		 rpf_addr_str);
  550:     }
  551: 
  552:     /* consider only (S,G) upstream in Joined state */
  553:     if (up->join_state != PIM_UPSTREAM_JOINED)
  554:       continue;
  555: 
  556:     /* match RPF'(S,G)=neigh_addr */
  557:     if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
  558:       continue;
  559: 
  560:     pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
  561: 						   up, neigh_addr);
  562:   }
  563: }
  564: 
  565: 
  566: void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
  567: 					struct interface *old_rpf_ifp)
  568: {
  569:   struct listnode  *ifnode;
  570:   struct listnode  *ifnextnode;
  571:   struct interface *ifp;
  572: 
  573:   /* scan all interfaces */
  574:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  575:     struct listnode      *chnode;
  576:     struct listnode      *chnextnode;
  577:     struct pim_ifchannel *ch;
  578:     struct pim_interface *pim_ifp;
  579: 
  580:     pim_ifp = ifp->info;
  581:     if (!pim_ifp)
  582:       continue;
  583: 
  584:     /* search all ifchannels */
  585:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  586:       if (ch->upstream != up)
  587: 	continue;
  588: 
  589:       if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
  590: 	if (
  591: 	    /* RPF_interface(S) was NOT I */
  592: 	    (old_rpf_ifp == ch->interface)
  593: 	    &&
  594: 	    /* RPF_interface(S) stopped being I */
  595: 	    (ch->upstream->rpf.source_nexthop.interface != ch->interface)
  596: 	    ) {
  597: 	  assert_action_a5(ch);
  598: 	}
  599:       } /* PIM_IFASSERT_I_AM_LOSER */
  600: 
  601:       pim_ifchannel_update_assert_tracking_desired(ch);
  602:     }
  603:   }
  604: }
  605: 
  606: void pim_upstream_update_could_assert(struct pim_upstream *up)
  607: {
  608:   struct listnode      *ifnode;
  609:   struct listnode      *ifnextnode;
  610:   struct listnode      *chnode;
  611:   struct listnode      *chnextnode;
  612:   struct interface     *ifp;
  613:   struct pim_interface *pim_ifp;
  614:   struct pim_ifchannel *ch;
  615: 
  616:   /* scan all interfaces */
  617:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  618:     pim_ifp = ifp->info;
  619:     if (!pim_ifp)
  620:       continue;
  621: 
  622:     /* scan per-interface (S,G) state */
  623:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  624: 
  625:       if (ch->upstream != up)
  626: 	continue;
  627: 
  628:       pim_ifchannel_update_could_assert(ch);
  629: 
  630:     } /* scan iface channel list */
  631:   } /* scan iflist */
  632: }
  633: 
  634: void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
  635: {
  636:   struct listnode      *ifnode;
  637:   struct listnode      *ifnextnode;
  638:   struct listnode      *chnode;
  639:   struct listnode      *chnextnode;
  640:   struct interface     *ifp;
  641:   struct pim_interface *pim_ifp;
  642:   struct pim_ifchannel *ch;
  643: 
  644:   /* scan all interfaces */
  645:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  646:     pim_ifp = ifp->info;
  647:     if (!pim_ifp)
  648:       continue;
  649: 
  650:     /* scan per-interface (S,G) state */
  651:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  652: 
  653:       if (ch->upstream != up)
  654: 	continue;
  655: 
  656:       pim_ifchannel_update_my_assert_metric(ch);
  657: 
  658:     } /* scan iface channel list */
  659:   } /* scan iflist */
  660: }
  661: 
  662: static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
  663: {
  664:   struct listnode      *ifnode;
  665:   struct listnode      *ifnextnode;
  666:   struct listnode      *chnode;
  667:   struct listnode      *chnextnode;
  668:   struct interface     *ifp;
  669:   struct pim_interface *pim_ifp;
  670:   struct pim_ifchannel *ch;
  671: 
  672:   /* scan all interfaces */
  673:   for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
  674:     pim_ifp = ifp->info;
  675:     if (!pim_ifp)
  676:       continue;
  677: 
  678:     /* scan per-interface (S,G) state */
  679:     for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
  680: 
  681:       if (ch->upstream != up)
  682: 	continue;
  683: 
  684:       pim_ifchannel_update_assert_tracking_desired(ch);
  685: 
  686:     } /* scan iface channel list */
  687:   } /* scan iflist */
  688: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>