Annotation of embedaddon/quagga/pimd/pim_upstream.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 "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>