Annotation of embedaddon/quagga/pimd/pim_ifchannel.c, revision 1.1.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 "linklist.h"
                     26: #include "thread.h"
                     27: #include "memory.h"
                     28: 
                     29: #include "pimd.h"
                     30: #include "pim_str.h"
                     31: #include "pim_iface.h"
                     32: #include "pim_ifchannel.h"
                     33: #include "pim_zebra.h"
                     34: #include "pim_time.h"
                     35: #include "pim_msg.h"
                     36: #include "pim_pim.h"
                     37: #include "pim_join.h"
                     38: #include "pim_rpf.h"
                     39: #include "pim_macro.h"
                     40: 
                     41: void pim_ifchannel_free(struct pim_ifchannel *ch)
                     42: {
                     43:   zassert(!ch->t_ifjoin_expiry_timer);
                     44:   zassert(!ch->t_ifjoin_prune_pending_timer);
                     45:   zassert(!ch->t_ifassert_timer);
                     46: 
                     47:   XFREE(MTYPE_PIM_IFCHANNEL, ch);
                     48: }
                     49: 
                     50: void pim_ifchannel_delete(struct pim_ifchannel *ch)
                     51: {
                     52:   struct pim_interface *pim_ifp;
                     53: 
                     54:   pim_ifp = ch->interface->info;
                     55:   zassert(pim_ifp);
                     56: 
                     57:   if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
                     58:     pim_upstream_update_join_desired(ch->upstream);
                     59:   }
                     60: 
                     61:   pim_upstream_del(ch->upstream);
                     62: 
                     63:   THREAD_OFF(ch->t_ifjoin_expiry_timer);
                     64:   THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
                     65:   THREAD_OFF(ch->t_ifassert_timer);
                     66: 
                     67:   /*
                     68:     notice that listnode_delete() can't be moved
                     69:     into pim_ifchannel_free() because the later is
                     70:     called by list_delete_all_node()
                     71:   */
                     72:   listnode_delete(pim_ifp->pim_ifchannel_list, ch);
                     73: 
                     74:   pim_ifchannel_free(ch);
                     75: }
                     76: 
                     77: #define IFCHANNEL_NOINFO(ch)                                   \
                     78:   (                                                            \
                     79:    ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)       \
                     80:    &&                                                          \
                     81:    ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO)                   \
                     82:    &&                                                          \
                     83:    ((ch)->ifassert_state == PIM_IFASSERT_NOINFO)               \
                     84:    )
                     85:    
                     86: static void delete_on_noinfo(struct pim_ifchannel *ch)
                     87: {
                     88:   if (IFCHANNEL_NOINFO(ch)) {
                     89: 
                     90:     /* In NOINFO state, timers should have been cleared */
                     91:     zassert(!ch->t_ifjoin_expiry_timer);
                     92:     zassert(!ch->t_ifjoin_prune_pending_timer);
                     93:     zassert(!ch->t_ifassert_timer);
                     94:     
                     95:     pim_ifchannel_delete(ch);
                     96:   }
                     97: }
                     98: 
                     99: void pim_ifchannel_ifjoin_switch(const char *caller,
                    100:                                 struct pim_ifchannel *ch,
                    101:                                 enum pim_ifjoin_state new_state)
                    102: {
                    103:   enum pim_ifjoin_state old_state = ch->ifjoin_state;
                    104: 
                    105:   if (old_state == new_state) {
                    106:     if (PIM_DEBUG_PIM_EVENTS) {
                    107:       zlog_debug("%s calledby %s: non-transition on state %d (%s)",
                    108:                 __PRETTY_FUNCTION__, caller, new_state,
                    109:                 pim_ifchannel_ifjoin_name(new_state));
                    110:     }
                    111:     return;
                    112:   }
                    113: 
                    114:   zassert(old_state != new_state);
                    115: 
                    116:   ch->ifjoin_state = new_state;
                    117: 
                    118:   /* Transition to/from NOINFO ? */
                    119:   if (
                    120:       (old_state == PIM_IFJOIN_NOINFO)
                    121:       ||
                    122:       (new_state == PIM_IFJOIN_NOINFO)
                    123:       ) {
                    124: 
                    125:     if (PIM_DEBUG_PIM_EVENTS) {
                    126:       char src_str[100];
                    127:       char grp_str[100];
                    128:       pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    129:       pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    130:       zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
                    131:                 ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
                    132:                 src_str, grp_str, ch->interface->name);
                    133:     }
                    134: 
                    135:     /*
                    136:       Record uptime of state transition to/from NOINFO
                    137:     */
                    138:     ch->ifjoin_creation = pim_time_monotonic_sec();
                    139: 
                    140:     pim_upstream_update_join_desired(ch->upstream);
                    141:     pim_ifchannel_update_could_assert(ch);
                    142:     pim_ifchannel_update_assert_tracking_desired(ch);
                    143:   }
                    144: }
                    145: 
                    146: const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
                    147: {
                    148:   switch (ifjoin_state) {
                    149:   case PIM_IFJOIN_NOINFO:        return "NOINFO";
                    150:   case PIM_IFJOIN_JOIN:          return "JOIN";
                    151:   case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
                    152:   }
                    153: 
                    154:   return "ifjoin_bad_state";
                    155: }
                    156: 
                    157: const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
                    158: {
                    159:   switch (ifassert_state) {
                    160:   case PIM_IFASSERT_NOINFO:      return "NOINFO";
                    161:   case PIM_IFASSERT_I_AM_WINNER: return "WINNER";
                    162:   case PIM_IFASSERT_I_AM_LOSER:  return "LOSER";
                    163:   }
                    164: 
                    165:   return "ifassert_bad_state";
                    166: }
                    167: 
                    168: /*
                    169:   RFC 4601: 4.6.5.  Assert State Macros
                    170: 
                    171:   AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
                    172:   defaults to Infinity when in the NoInfo state.
                    173: */
                    174: void reset_ifassert_state(struct pim_ifchannel *ch)
                    175: {
                    176:   THREAD_OFF(ch->t_ifassert_timer);
                    177: 
                    178:   pim_ifassert_winner_set(ch,
                    179:                          PIM_IFASSERT_NOINFO,
                    180:                          qpim_inaddr_any,
                    181:                          qpim_infinite_assert_metric);
                    182: }
                    183: 
                    184: static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp,
                    185:                                               struct in_addr source_addr,
                    186:                                               struct in_addr group_addr)
                    187: {
                    188:   struct pim_ifchannel *ch;
                    189:   struct pim_interface *pim_ifp;
                    190:   struct pim_upstream  *up;
                    191: 
                    192:   pim_ifp = ifp->info;
                    193:   zassert(pim_ifp);
                    194: 
                    195:   up = pim_upstream_add(source_addr, group_addr);
                    196:   if (!up) {
                    197:     char src_str[100];
                    198:     char grp_str[100];
                    199:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    200:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    201:     zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
                    202:             __PRETTY_FUNCTION__,
                    203:             src_str, grp_str, ifp->name);
                    204:     return 0;
                    205:   }
                    206: 
                    207:   ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
                    208:   if (!ch) {
                    209:     zlog_err("%s: PIM XMALLOC(%zu) failure",
                    210:             __PRETTY_FUNCTION__, sizeof(*ch));
                    211:     return 0;
                    212:   }
                    213: 
                    214:   ch->flags                        = 0;
                    215:   ch->upstream                     = up;
                    216:   ch->interface                    = ifp;
                    217:   ch->source_addr                  = source_addr;
                    218:   ch->group_addr                   = group_addr;
                    219:   ch->local_ifmembership           = PIM_IFMEMBERSHIP_NOINFO;
                    220: 
                    221:   ch->ifjoin_state                 = PIM_IFJOIN_NOINFO;
                    222:   ch->t_ifjoin_expiry_timer        = 0;
                    223:   ch->t_ifjoin_prune_pending_timer = 0;
                    224:   ch->ifjoin_creation              = 0;
                    225: 
                    226:   /* Assert state */
                    227:   ch->t_ifassert_timer   = 0;
                    228:   reset_ifassert_state(ch);
                    229:   if (pim_macro_ch_could_assert_eval(ch))
                    230:     PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
                    231:   else
                    232:     PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
                    233: 
                    234:   if (pim_macro_assert_tracking_desired_eval(ch))
                    235:     PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
                    236:   else
                    237:     PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
                    238: 
                    239:   ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
                    240: 
                    241:   /* Attach to list */
                    242:   listnode_add(pim_ifp->pim_ifchannel_list, ch);
                    243: 
                    244:   zassert(IFCHANNEL_NOINFO(ch));
                    245: 
                    246:   return ch;
                    247: }
                    248: 
                    249: struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
                    250:                                         struct in_addr source_addr,
                    251:                                         struct in_addr group_addr)
                    252: {
                    253:   struct pim_interface *pim_ifp;
                    254:   struct listnode      *ch_node;
                    255:   struct pim_ifchannel *ch;
                    256: 
                    257:   zassert(ifp);
                    258: 
                    259:   pim_ifp = ifp->info;
                    260: 
                    261:   if (!pim_ifp) {
                    262:     char src_str[100];
                    263:     char grp_str[100];
                    264:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    265:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    266:     zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
                    267:              __PRETTY_FUNCTION__,
                    268:              src_str, grp_str,
                    269:              ifp->name);
                    270:     return 0;
                    271:   }
                    272: 
                    273:   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
                    274:     if (
                    275:        (source_addr.s_addr == ch->source_addr.s_addr) &&
                    276:        (group_addr.s_addr == ch->group_addr.s_addr)
                    277:        ) {
                    278:       return ch;
                    279:     }
                    280:   }
                    281: 
                    282:   return 0;
                    283: }
                    284: 
                    285: static void ifmembership_set(struct pim_ifchannel *ch,
                    286:                             enum pim_ifmembership membership)
                    287: {
                    288:   if (ch->local_ifmembership == membership)
                    289:     return;
                    290: 
                    291:   if (PIM_DEBUG_PIM_EVENTS) {
                    292:     char src_str[100];
                    293:     char grp_str[100];
                    294:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    295:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    296:     zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
                    297:               __PRETTY_FUNCTION__,
                    298:               src_str, grp_str,
                    299:               membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
                    300:               ch->interface->name);
                    301:   }
                    302:   
                    303:   ch->local_ifmembership = membership;
                    304: 
                    305:   pim_upstream_update_join_desired(ch->upstream);
                    306:   pim_ifchannel_update_could_assert(ch);
                    307:   pim_ifchannel_update_assert_tracking_desired(ch);
                    308: }
                    309: 
                    310: 
                    311: void pim_ifchannel_membership_clear(struct interface *ifp)
                    312: {
                    313:   struct pim_interface *pim_ifp;
                    314:   struct listnode      *ch_node;
                    315:   struct pim_ifchannel *ch;
                    316: 
                    317:   pim_ifp = ifp->info;
                    318:   zassert(pim_ifp);
                    319: 
                    320:   for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
                    321:     ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
                    322:   }
                    323: }
                    324: 
                    325: void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
                    326: {
                    327:   struct pim_interface *pim_ifp;
                    328:   struct listnode      *node;
                    329:   struct listnode      *next_node;
                    330:   struct pim_ifchannel *ch;
                    331: 
                    332:   pim_ifp = ifp->info;
                    333:   zassert(pim_ifp);
                    334: 
                    335:   for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
                    336:     delete_on_noinfo(ch);
                    337:   }
                    338: }
                    339: 
                    340: struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
                    341:                                        struct in_addr source_addr,
                    342:                                        struct in_addr group_addr)
                    343: {
                    344:   struct pim_ifchannel *ch;
                    345:   char src_str[100];
                    346:   char grp_str[100];
                    347: 
                    348:   ch = pim_ifchannel_find(ifp, source_addr, group_addr);
                    349:   if (ch)
                    350:     return ch;
                    351: 
                    352:   ch = pim_ifchannel_new(ifp, source_addr, group_addr);
                    353:   if (ch)
                    354:     return ch;
                    355:     
                    356:   pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    357:   pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    358:   zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
                    359:            __PRETTY_FUNCTION__,
                    360:            src_str, grp_str, ifp->name);
                    361: 
                    362:   return 0;
                    363: }
                    364: 
                    365: static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
                    366: {
                    367:   pim_forward_stop(ch);
                    368:   pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
                    369:   delete_on_noinfo(ch);
                    370: }
                    371: 
                    372: static int on_ifjoin_expiry_timer(struct thread *t)
                    373: {
                    374:   struct pim_ifchannel *ch;
                    375: 
                    376:   zassert(t);
                    377:   ch = THREAD_ARG(t);
                    378:   zassert(ch);
                    379: 
                    380:   ch->t_ifjoin_expiry_timer = 0;
                    381: 
                    382:   zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN);
                    383: 
                    384:   ifjoin_to_noinfo(ch);
                    385:   /* ch may have been deleted */
                    386: 
                    387:   return 0;
                    388: }
                    389: 
                    390: static void prune_echo(struct interface *ifp,
                    391:                       struct in_addr source_addr,
                    392:                       struct in_addr group_addr)
                    393: {
                    394:   struct pim_interface *pim_ifp;
                    395:   struct in_addr neigh_dst_addr;
                    396: 
                    397:   pim_ifp = ifp->info;
                    398:   zassert(pim_ifp);
                    399: 
                    400:   neigh_dst_addr = pim_ifp->primary_address;
                    401: 
                    402:   if (PIM_DEBUG_PIM_EVENTS) {
                    403:     char source_str[100];
                    404:     char group_str[100];
                    405:     char neigh_dst_str[100];
                    406:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
                    407:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
                    408:     pim_inet4_dump("<neigh?>", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str));
                    409:     zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
                    410:               __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name);
                    411:   }
                    412: 
                    413:   pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr,
                    414:                     0 /* boolean: send_join=false (prune) */);
                    415: }
                    416: 
                    417: static int on_ifjoin_prune_pending_timer(struct thread *t)
                    418: {
                    419:   struct pim_ifchannel *ch;
                    420:   int send_prune_echo; /* boolean */
                    421:   struct interface *ifp;
                    422:   struct pim_interface *pim_ifp;
                    423:   struct in_addr ch_source;
                    424:   struct in_addr ch_group;
                    425: 
                    426:   zassert(t);
                    427:   ch = THREAD_ARG(t);
                    428:   zassert(ch);
                    429: 
                    430:   ch->t_ifjoin_prune_pending_timer = 0;
                    431: 
                    432:   zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING);
                    433: 
                    434:   /* Send PruneEcho(S,G) ? */
                    435:   ifp = ch->interface;
                    436:   pim_ifp = ifp->info;
                    437:   send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
                    438: 
                    439:   /* Save (S,G) */
                    440:   ch_source = ch->source_addr;
                    441:   ch_group = ch->group_addr;
                    442: 
                    443:   ifjoin_to_noinfo(ch);
                    444:   /* from here ch may have been deleted */
                    445: 
                    446:   if (send_prune_echo)
                    447:     prune_echo(ifp, ch_source, ch_group);
                    448: 
                    449:   return 0;
                    450: }
                    451: 
                    452: static void check_recv_upstream(int is_join,
                    453:                                struct interface *recv_ifp,
                    454:                                struct in_addr upstream,
                    455:                                struct in_addr source_addr,
                    456:                                struct in_addr group_addr,
                    457:                                uint8_t source_flags,
                    458:                                int holdtime)
                    459: {
                    460:   struct pim_upstream *up;
                    461: 
                    462:   /* Upstream (S,G) in Joined state ? */
                    463:   up = pim_upstream_find(source_addr, group_addr);
                    464:   if (!up)
                    465:     return;
                    466:   if (up->join_state != PIM_UPSTREAM_JOINED)
                    467:     return;
                    468: 
                    469:   /* Upstream (S,G) in Joined state */
                    470: 
                    471:   if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
                    472:     /* RPF'(S,G) not found */
                    473:     char src_str[100];
                    474:     char grp_str[100];
                    475:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    476:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    477:     zlog_warn("%s %s: RPF'(%s,%s) not found",
                    478:              __FILE__, __PRETTY_FUNCTION__, 
                    479:              src_str, grp_str);
                    480:     return;
                    481:   }
                    482: 
                    483:   /* upstream directed to RPF'(S,G) ? */
                    484:   if (upstream.s_addr != up->rpf.rpf_addr.s_addr) {
                    485:     char src_str[100];
                    486:     char grp_str[100];
                    487:     char up_str[100];
                    488:     char rpf_str[100];
                    489:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    490:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    491:     pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
                    492:     pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
                    493:     zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
                    494:              __FILE__, __PRETTY_FUNCTION__, 
                    495:              src_str, grp_str,
                    496:              up_str, rpf_str, recv_ifp->name);
                    497:     return;
                    498:   }
                    499:   /* upstream directed to RPF'(S,G) */
                    500: 
                    501:   if (is_join) {
                    502:     /* Join(S,G) to RPF'(S,G) */
                    503:     pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
                    504:     return;
                    505:   }
                    506: 
                    507:   /* Prune to RPF'(S,G) */
                    508: 
                    509:   if (source_flags & PIM_RPT_BIT_MASK) {
                    510:     if (source_flags & PIM_WILDCARD_BIT_MASK) {
                    511:       /* Prune(*,G) to RPF'(S,G) */
                    512:       pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
                    513:                                                     up, up->rpf.rpf_addr);
                    514:       return;
                    515:     }
                    516: 
                    517:     /* Prune(S,G,rpt) to RPF'(S,G) */
                    518:     pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
                    519:                                                   up, up->rpf.rpf_addr);
                    520:     return;
                    521:   }
                    522: 
                    523:   /* Prune(S,G) to RPF'(S,G) */
                    524:   pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
                    525:                                                 up->rpf.rpf_addr);
                    526: }
                    527: 
                    528: static int nonlocal_upstream(int is_join,
                    529:                             struct interface *recv_ifp,
                    530:                             struct in_addr upstream,
                    531:                             struct in_addr source_addr,
                    532:                             struct in_addr group_addr,
                    533:                             uint8_t source_flags,
                    534:                             uint16_t holdtime)
                    535: {
                    536:   struct pim_interface *recv_pim_ifp;
                    537:   int is_local; /* boolean */
                    538: 
                    539:   recv_pim_ifp = recv_ifp->info;
                    540:   zassert(recv_pim_ifp);
                    541: 
                    542:   is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
                    543:   
                    544:   if (PIM_DEBUG_PIM_TRACE) {
                    545:     char up_str[100];
                    546:     char src_str[100];
                    547:     char grp_str[100];
                    548:     pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
                    549:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    550:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    551:     zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
                    552:              __PRETTY_FUNCTION__,
                    553:              is_join ? "join" : "prune",
                    554:              src_str, grp_str,
                    555:              is_local ? "local" : "non-local",
                    556:              up_str, recv_ifp->name);
                    557:   }
                    558: 
                    559:   if (is_local)
                    560:     return 0;
                    561: 
                    562:   /*
                    563:     Since recv upstream addr was not directed to our primary
                    564:     address, check if we should react to it in any way.
                    565:   */
                    566:   check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr,
                    567:                      source_flags, holdtime);
                    568: 
                    569:   return 1; /* non-local */
                    570: }
                    571: 
                    572: void pim_ifchannel_join_add(struct interface *ifp,
                    573:                            struct in_addr neigh_addr,
                    574:                            struct in_addr upstream,
                    575:                            struct in_addr source_addr,
                    576:                            struct in_addr group_addr,
                    577:                            uint8_t source_flags,
                    578:                            uint16_t holdtime)
                    579: {
                    580:   struct pim_interface *pim_ifp;
                    581:   struct pim_ifchannel *ch;
                    582: 
                    583:   if (nonlocal_upstream(1 /* join */, ifp, upstream,
                    584:                        source_addr, group_addr, source_flags, holdtime)) {
                    585:     return;
                    586:   }
                    587: 
                    588:   ch = pim_ifchannel_add(ifp, source_addr, group_addr);
                    589:   if (!ch)
                    590:     return;
                    591: 
                    592:   /*
                    593:     RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    594: 
                    595:     Transitions from "I am Assert Loser" State
                    596: 
                    597:     Receive Join(S,G) on Interface I
                    598: 
                    599:     We receive a Join(S,G) that has the Upstream Neighbor Address
                    600:     field set to my primary IP address on interface I.  The action is
                    601:     to transition to NoInfo state, delete this (S,G) assert state
                    602:     (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
                    603:     to operate.
                    604: 
                    605:     Notice: The nonlocal_upstream() test above ensures the upstream
                    606:     address of the join message is our primary address.
                    607:    */
                    608:   if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
                    609:     char src_str[100];
                    610:     char grp_str[100];
                    611:     char neigh_str[100];
                    612:     pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
                    613:     pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
                    614:     pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
                    615:     zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
                    616:              __PRETTY_FUNCTION__,
                    617:              src_str, grp_str, neigh_str, ifp->name);
                    618: 
                    619:     assert_action_a5(ch);
                    620:   }
                    621: 
                    622:   pim_ifp = ifp->info;
                    623:   zassert(pim_ifp);
                    624: 
                    625:   switch (ch->ifjoin_state) {
                    626:   case PIM_IFJOIN_NOINFO:
                    627:     pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
                    628:     if (pim_macro_chisin_oiflist(ch)) {
                    629:       pim_forward_start(ch);
                    630:     }
                    631:     break;
                    632:   case PIM_IFJOIN_JOIN:
                    633:     zassert(!ch->t_ifjoin_prune_pending_timer);
                    634: 
                    635:     /*
                    636:       In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
                    637:       previously received join message with holdtime=0xFFFF.
                    638:      */
                    639:     if (ch->t_ifjoin_expiry_timer) {
                    640:       unsigned long remain =
                    641:        thread_timer_remain_second(ch->t_ifjoin_expiry_timer);
                    642:       if (remain > holdtime) {
                    643:        /*
                    644:          RFC 4601: 4.5.3.  Receiving (S,G) Join/Prune Messages
                    645: 
                    646:          Transitions from Join State
                    647: 
                    648:           The (S,G) downstream state machine on interface I remains in
                    649:           Join state, and the Expiry Timer (ET) is restarted, set to
                    650:           maximum of its current value and the HoldTime from the
                    651:           triggering Join/Prune message.
                    652: 
                    653:          Conclusion: Do not change the ET if the current value is
                    654:          higher than the received join holdtime.
                    655:         */
                    656:        return;
                    657:       }
                    658:     }
                    659:     THREAD_OFF(ch->t_ifjoin_expiry_timer);
                    660:     break;
                    661:   case PIM_IFJOIN_PRUNE_PENDING:
                    662:     zassert(!ch->t_ifjoin_expiry_timer);
                    663:     zassert(ch->t_ifjoin_prune_pending_timer);
                    664:     THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
                    665:     pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
                    666:     break;
                    667:   }
                    668: 
                    669:   zassert(!IFCHANNEL_NOINFO(ch));
                    670: 
                    671:   if (holdtime != 0xFFFF) {
                    672:     THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
                    673:                    on_ifjoin_expiry_timer,
                    674:                    ch, holdtime);
                    675:   }
                    676: }
                    677: 
                    678: void pim_ifchannel_prune(struct interface *ifp,
                    679:                         struct in_addr upstream,
                    680:                         struct in_addr source_addr,
                    681:                         struct in_addr group_addr,
                    682:                         uint8_t source_flags,
                    683:                         uint16_t holdtime)
                    684: {
                    685:   struct pim_ifchannel *ch;
                    686:   int jp_override_interval_msec;
                    687: 
                    688:   if (nonlocal_upstream(0 /* prune */, ifp, upstream,
                    689:                        source_addr, group_addr, source_flags, holdtime)) {
                    690:     return;
                    691:   }
                    692: 
                    693:   ch = pim_ifchannel_add(ifp, source_addr, group_addr);
                    694:   if (!ch)
                    695:     return;
                    696: 
                    697:   switch (ch->ifjoin_state) {
                    698:   case PIM_IFJOIN_NOINFO:
                    699:   case PIM_IFJOIN_PRUNE_PENDING:
                    700:     /* nothing to do */
                    701:     break;
                    702:   case PIM_IFJOIN_JOIN:
                    703:     {
                    704:       struct pim_interface *pim_ifp;
                    705: 
                    706:       pim_ifp = ifp->info;
                    707: 
                    708:       zassert(ch->t_ifjoin_expiry_timer);
                    709:       zassert(!ch->t_ifjoin_prune_pending_timer);
                    710: 
                    711:       THREAD_OFF(ch->t_ifjoin_expiry_timer);
                    712:       
                    713:       pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
                    714:       
                    715:       if (listcount(pim_ifp->pim_neighbor_list) > 1) {
                    716:        jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
                    717:       }
                    718:       else {
                    719:        jp_override_interval_msec = 0; /* schedule to expire immediately */
                    720:        /* If we called ifjoin_prune() directly instead, care should
                    721:           be taken not to use "ch" afterwards since it would be
                    722:           deleted. */
                    723:       }
                    724:       
                    725:       THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
                    726:                           on_ifjoin_prune_pending_timer,
                    727:                           ch, jp_override_interval_msec);
                    728:       
                    729:       zassert(!ch->t_ifjoin_expiry_timer);
                    730:       zassert(ch->t_ifjoin_prune_pending_timer);
                    731:     }
                    732:     break;
                    733:   }
                    734: 
                    735: }
                    736: 
                    737: void pim_ifchannel_local_membership_add(struct interface *ifp,
                    738:                                        struct in_addr source_addr,
                    739:                                        struct in_addr group_addr)
                    740: {
                    741:   struct pim_ifchannel *ch;
                    742:   struct pim_interface *pim_ifp;
                    743: 
                    744:   /* PIM enabled on interface? */
                    745:   pim_ifp = ifp->info;
                    746:   if (!pim_ifp)
                    747:     return;
                    748:   if (!PIM_IF_TEST_PIM(pim_ifp->options))
                    749:     return;
                    750: 
                    751:   ch = pim_ifchannel_add(ifp, source_addr, group_addr);
                    752:   if (!ch) {
                    753:     return;
                    754:   }
                    755: 
                    756:   ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
                    757: 
                    758:   zassert(!IFCHANNEL_NOINFO(ch));
                    759: }
                    760: 
                    761: void pim_ifchannel_local_membership_del(struct interface *ifp,
                    762:                                        struct in_addr source_addr,
                    763:                                        struct in_addr group_addr)
                    764: {
                    765:   struct pim_ifchannel *ch;
                    766:   struct pim_interface *pim_ifp;
                    767: 
                    768:   /* PIM enabled on interface? */
                    769:   pim_ifp = ifp->info;
                    770:   if (!pim_ifp)
                    771:     return;
                    772:   if (!PIM_IF_TEST_PIM(pim_ifp->options))
                    773:     return;
                    774: 
                    775:   ch = pim_ifchannel_find(ifp, source_addr, group_addr);
                    776:   if (!ch)
                    777:     return;
                    778: 
                    779:   ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
                    780: 
                    781:   delete_on_noinfo(ch);
                    782: }
                    783: 
                    784: void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
                    785: {
                    786:   int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
                    787:   int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
                    788: 
                    789:   if (new_couldassert == old_couldassert)
                    790:     return;
                    791: 
                    792:   if (PIM_DEBUG_PIM_EVENTS) {
                    793:     char src_str[100];
                    794:     char grp_str[100];
                    795:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    796:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    797:     zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
                    798:               __PRETTY_FUNCTION__,
                    799:               src_str, grp_str, ch->interface->name,
                    800:               old_couldassert, new_couldassert);
                    801:   }
                    802: 
                    803:   if (new_couldassert) {
                    804:     /* CouldAssert(S,G,I) switched from FALSE to TRUE */
                    805:     PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
                    806:   }
                    807:   else {
                    808:     /* CouldAssert(S,G,I) switched from TRUE to FALSE */
                    809:     PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
                    810: 
                    811:     if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
                    812:       assert_action_a4(ch);
                    813:     }
                    814:   }
                    815: 
                    816:   pim_ifchannel_update_my_assert_metric(ch);
                    817: }
                    818: 
                    819: /*
                    820:   my_assert_metric may be affected by:
                    821: 
                    822:   CouldAssert(S,G)
                    823:   pim_ifp->primary_address
                    824:   rpf->source_nexthop.mrib_metric_preference;
                    825:   rpf->source_nexthop.mrib_route_metric;
                    826:  */
                    827: void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
                    828: {
                    829:   struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch);
                    830: 
                    831:   if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
                    832:       return;
                    833: 
                    834:   if (PIM_DEBUG_PIM_EVENTS) {
                    835:     char src_str[100];
                    836:     char grp_str[100];
                    837:     char old_addr_str[100];
                    838:     char new_addr_str[100];
                    839:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    840:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    841:     pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
                    842:     pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
                    843:     zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
                    844:               __PRETTY_FUNCTION__,
                    845:               src_str, grp_str, ch->interface->name,
                    846:               ch->ifassert_my_metric.rpt_bit_flag,
                    847:               ch->ifassert_my_metric.metric_preference,
                    848:               ch->ifassert_my_metric.route_metric,
                    849:               old_addr_str,
                    850:               my_metric_new.rpt_bit_flag,
                    851:               my_metric_new.metric_preference,
                    852:               my_metric_new.route_metric,
                    853:               new_addr_str);
                    854:   }
                    855: 
                    856:   ch->ifassert_my_metric = my_metric_new;
                    857: 
                    858:   if (pim_assert_metric_better(&ch->ifassert_my_metric,
                    859:                               &ch->ifassert_winner_metric)) {
                    860:     assert_action_a5(ch);
                    861:   }
                    862: }
                    863: 
                    864: void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
                    865: {
                    866:   int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
                    867:   int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
                    868: 
                    869:   if (new_atd == old_atd)
                    870:     return;
                    871: 
                    872:   if (PIM_DEBUG_PIM_EVENTS) {
                    873:     char src_str[100];
                    874:     char grp_str[100];
                    875:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    876:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    877:     zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
                    878:               __PRETTY_FUNCTION__,
                    879:               src_str, grp_str, ch->interface->name,
                    880:               old_atd, new_atd);
                    881:   }
                    882: 
                    883:   if (new_atd) {
                    884:     /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
                    885:     PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
                    886:   }
                    887:   else {
                    888:     /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
                    889:     PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
                    890: 
                    891:     if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
                    892:       assert_action_a5(ch);
                    893:     }
                    894:   }
                    895: }

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