Annotation of embedaddon/quagga/pimd/pim_assert.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 "log.h"
                     26: #include "prefix.h"
                     27: 
                     28: #include "pimd.h"
                     29: #include "pim_str.h"
                     30: #include "pim_tlv.h"
                     31: #include "pim_msg.h"
                     32: #include "pim_pim.h"
                     33: #include "pim_int.h"
                     34: #include "pim_time.h"
                     35: #include "pim_iface.h"
                     36: #include "pim_hello.h"
                     37: #include "pim_macro.h"
                     38: #include "pim_assert.h"
                     39: #include "pim_ifchannel.h"
                     40: 
                     41: static int assert_action_a3(struct pim_ifchannel *ch);
                     42: static void assert_action_a2(struct pim_ifchannel *ch,
                     43:                             struct pim_assert_metric winner_metric);
                     44: static void assert_action_a6(struct pim_ifchannel *ch,
                     45:                             struct pim_assert_metric winner_metric);
                     46: 
                     47: void pim_ifassert_winner_set(struct pim_ifchannel     *ch,
                     48:                             enum pim_ifassert_state   new_state,
                     49:                             struct in_addr            winner,
                     50:                             struct pim_assert_metric  winner_metric)
                     51: {
                     52:   int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
                     53:   int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric,
                     54:                                                &winner_metric);
                     55: 
                     56:   if (PIM_DEBUG_PIM_EVENTS) {
                     57:     if (ch->ifassert_state != new_state) {
                     58:       char src_str[100];
                     59:       char grp_str[100];
                     60:       pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                     61:       pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                     62:       zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
                     63:                __PRETTY_FUNCTION__,
                     64:                src_str, grp_str,
                     65:                pim_ifchannel_ifassert_name(ch->ifassert_state),
                     66:                pim_ifchannel_ifassert_name(new_state),
                     67:                ch->interface->name);
                     68:     }
                     69: 
                     70:     if (winner_changed) {
                     71:       char src_str[100];
                     72:       char grp_str[100];
                     73:       char was_str[100];
                     74:       char winner_str[100];
                     75:       pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                     76:       pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                     77:       pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
                     78:       pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
                     79:       zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
                     80:                __PRETTY_FUNCTION__,
                     81:                src_str, grp_str,
                     82:                was_str, winner_str, ch->interface->name);
                     83:     }
                     84:   } /* PIM_DEBUG_PIM_EVENTS */
                     85: 
                     86:   ch->ifassert_state         = new_state;
                     87:   ch->ifassert_winner        = winner;
                     88:   ch->ifassert_winner_metric = winner_metric;
                     89:   ch->ifassert_creation      = pim_time_monotonic_sec();
                     90: 
                     91:   if (winner_changed || metric_changed) {
                     92:     pim_upstream_update_join_desired(ch->upstream);
                     93:     pim_ifchannel_update_could_assert(ch);
                     94:     pim_ifchannel_update_assert_tracking_desired(ch);
                     95:   }
                     96: }
                     97: 
                     98: static void on_trace(const char *label,
                     99:                     struct interface *ifp, struct in_addr src)
                    100: {
                    101:   if (PIM_DEBUG_PIM_TRACE) {
                    102:     char src_str[100];
                    103:     pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
                    104:     zlog_debug("%s: from %s on %s",
                    105:               label, src_str, ifp->name);
                    106:   }
                    107: }
                    108: 
                    109: static int preferred_assert(const struct pim_ifchannel *ch,
                    110:                            const struct pim_assert_metric *recv_metric)
                    111: {
                    112:   return pim_assert_metric_better(recv_metric,
                    113:                                  &ch->ifassert_winner_metric);
                    114: }
                    115: 
                    116: static int acceptable_assert(const struct pim_assert_metric *my_metric,
                    117:                             const struct pim_assert_metric *recv_metric)
                    118: {
                    119:   return pim_assert_metric_better(recv_metric,
                    120:                                  my_metric);
                    121: }
                    122: 
                    123: static int inferior_assert(const struct pim_assert_metric *my_metric,
                    124:                           const struct pim_assert_metric *recv_metric)
                    125: {
                    126:   return pim_assert_metric_better(my_metric,
                    127:                                  recv_metric);
                    128: }
                    129: 
                    130: static int cancel_assert(const struct pim_assert_metric *recv_metric)
                    131: {
                    132:   return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
                    133:     &&
                    134:     (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX);
                    135: }
                    136: 
                    137: static void if_could_assert_do_a1(const char *caller,
                    138:                                  struct pim_ifchannel *ch)
                    139: {
                    140:   if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
                    141:     if (assert_action_a1(ch)) {
                    142:       char src_str[100];
                    143:       char grp_str[100];
                    144:       pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    145:       pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    146:       zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
                    147:                __PRETTY_FUNCTION__, caller,
                    148:                src_str, grp_str, ch->interface->name);
                    149:       /* log warning only */
                    150:     }
                    151:   }
                    152: }
                    153: 
                    154: static int dispatch_assert(struct interface *ifp,
                    155:                           struct in_addr source_addr,
                    156:                           struct in_addr group_addr,
                    157:                           struct pim_assert_metric recv_metric)
                    158: {
                    159:   struct pim_ifchannel *ch;
                    160: 
                    161:   ch = pim_ifchannel_add(ifp, source_addr, group_addr);
                    162:   if (!ch) {
                    163:     char source_str[100];
                    164:     char group_str[100];
                    165:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
                    166:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
                    167:     zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
                    168:              __PRETTY_FUNCTION__,
                    169:              source_str, group_str, ifp->name);
                    170:     return -1;
                    171:   }
                    172: 
                    173:   switch (ch->ifassert_state) {
                    174:   case PIM_IFASSERT_NOINFO:
                    175:     if (recv_metric.rpt_bit_flag) {
                    176:       /* RPT bit set */
                    177:       if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
                    178:     }
                    179:     else {
                    180:       /* RPT bit clear */
                    181:       if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
                    182:        if_could_assert_do_a1(__PRETTY_FUNCTION__, ch);
                    183:       }
                    184:       else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
                    185:        if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) {
                    186:          assert_action_a6(ch, recv_metric);
                    187:        }
                    188:       }
                    189:     }
                    190:     break;
                    191:   case PIM_IFASSERT_I_AM_WINNER:
                    192:     if (preferred_assert(ch, &recv_metric)) {
                    193:       assert_action_a2(ch, recv_metric);
                    194:     }
                    195:     else {
                    196:       if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
                    197:        zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
                    198:        assert_action_a3(ch);
                    199:       }
                    200:     }
                    201:     break;
                    202:   case PIM_IFASSERT_I_AM_LOSER:
                    203:     if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) {
                    204:       /* Assert from current winner */
                    205: 
                    206:       if (cancel_assert(&recv_metric)) {
                    207:        assert_action_a5(ch);
                    208:       }
                    209:       else {
                    210:        if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
                    211:          assert_action_a5(ch);
                    212:        }
                    213:        else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) {
                    214:          if (!recv_metric.rpt_bit_flag) {
                    215:            assert_action_a2(ch, recv_metric);
                    216:          }
                    217:        }
                    218:       }
                    219:     }
                    220:     else if (preferred_assert(ch, &recv_metric)) {
                    221:       assert_action_a2(ch, recv_metric);
                    222:     }
                    223:     break;
                    224:   default:
                    225:     {
                    226:       char source_str[100];
                    227:       char group_str[100];
                    228:       pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
                    229:       pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
                    230:       zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
                    231:                __PRETTY_FUNCTION__,
                    232:                source_str, group_str, ch->ifassert_state, ifp->name);
                    233:     }
                    234:     return -2;
                    235:   }
                    236: 
                    237:   return 0;
                    238: }
                    239: 
                    240: int pim_assert_recv(struct interface *ifp,
                    241:                    struct pim_neighbor *neigh,
                    242:                    struct in_addr src_addr,
                    243:                    uint8_t *buf, int buf_size)
                    244: {
                    245:   struct prefix            msg_group_addr;
                    246:   struct prefix            msg_source_addr;
                    247:   struct pim_assert_metric msg_metric;
                    248:   int offset;
                    249:   uint8_t *curr;
                    250:   int curr_size;
                    251: 
                    252:   on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
                    253: 
                    254:   curr      = buf;
                    255:   curr_size = buf_size;
                    256: 
                    257:   /*
                    258:     Parse assert group addr
                    259:    */
                    260:   offset = pim_parse_addr_group(ifp->name, src_addr,
                    261:                                &msg_group_addr,
                    262:                                curr, curr_size);
                    263:   if (offset < 1) {
                    264:     char src_str[100];
                    265:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
                    266:     zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
                    267:              __PRETTY_FUNCTION__,
                    268:              src_str, ifp->name);
                    269:     return -1;
                    270:   }
                    271:   curr      += offset;
                    272:   curr_size -= offset;
                    273: 
                    274:   /*
                    275:     Parse assert source addr
                    276:   */
                    277:   offset = pim_parse_addr_ucast(ifp->name, src_addr,
                    278:                                &msg_source_addr,
                    279:                                curr, curr_size);
                    280:   if (offset < 1) {
                    281:     char src_str[100];
                    282:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
                    283:     zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
                    284:              __PRETTY_FUNCTION__,
                    285:              src_str, ifp->name);
                    286:     return -2;
                    287:   }
                    288:   curr      += offset;
                    289:   curr_size -= offset;
                    290: 
                    291:   if (curr_size != 8) {
                    292:     char src_str[100];
                    293:     pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
                    294:     zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
                    295:              __PRETTY_FUNCTION__,
                    296:              curr_size,
                    297:              src_str, ifp->name);
                    298:     return -3;
                    299:   }
                    300: 
                    301:   /*
                    302:     Parse assert metric preference
                    303:   */
                    304: 
                    305:   msg_metric.metric_preference = pim_read_uint32_host(curr);
                    306: 
                    307:   msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */
                    308:   msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */
                    309: 
                    310:   curr += 4;
                    311: 
                    312:   /*
                    313:     Parse assert route metric
                    314:   */
                    315: 
                    316:   msg_metric.route_metric = pim_read_uint32_host(curr);
                    317: 
                    318:   if (PIM_DEBUG_PIM_TRACE) {
                    319:     char neigh_str[100];
                    320:     char source_str[100];
                    321:     char group_str[100];
                    322:     pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
                    323:     pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
                    324:     pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
                    325:     zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
                    326:               __PRETTY_FUNCTION__, neigh_str, ifp->name,
                    327:               source_str, group_str,
                    328:               msg_metric.metric_preference,
                    329:               msg_metric.route_metric,
                    330:               PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag));
                    331:   }
                    332: 
                    333:   msg_metric.ip_address = src_addr;
                    334: 
                    335:   return dispatch_assert(ifp,
                    336:                         msg_source_addr.u.prefix4,
                    337:                         msg_group_addr.u.prefix4,
                    338:                         msg_metric);
                    339: }
                    340: 
                    341: /*
                    342:   RFC 4601: 4.6.3.  Assert Metrics
                    343: 
                    344:    Assert metrics are defined as:
                    345: 
                    346:    When comparing assert_metrics, the rpt_bit_flag, metric_preference,
                    347:    and route_metric field are compared in order, where the first lower
                    348:    value wins.  If all fields are equal, the primary IP address of the
                    349:    router that sourced the Assert message is used as a tie-breaker,
                    350:    with the highest IP address winning.
                    351: */
                    352: int pim_assert_metric_better(const struct pim_assert_metric *m1,
                    353:                             const struct pim_assert_metric *m2)
                    354: {
                    355:   if (m1->rpt_bit_flag < m2->rpt_bit_flag)
                    356:     return 1;
                    357:   if (m1->rpt_bit_flag > m2->rpt_bit_flag)
                    358:     return 0;
                    359: 
                    360:   if (m1->metric_preference < m2->metric_preference)
                    361:     return 1;
                    362:   if (m1->metric_preference > m2->metric_preference)
                    363:     return 0;
                    364: 
                    365:   if (m1->route_metric < m2->route_metric)
                    366:     return 1;
                    367:   if (m1->route_metric > m2->route_metric)
                    368:     return 0;
                    369: 
                    370:   return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr);
                    371: }
                    372: 
                    373: int pim_assert_metric_match(const struct pim_assert_metric *m1,
                    374:                            const struct pim_assert_metric *m2)
                    375: {
                    376:   if (m1->rpt_bit_flag != m2->rpt_bit_flag)
                    377:     return 0;
                    378:   if (m1->metric_preference != m2->metric_preference)
                    379:     return 0;
                    380:   if (m1->route_metric != m2->route_metric)
                    381:     return 0;
                    382:   
                    383:   return m1->ip_address.s_addr == m2->ip_address.s_addr;
                    384: }
                    385: 
                    386: int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
                    387:                         struct interface *ifp,
                    388:                         struct in_addr group_addr,
                    389:                         struct in_addr source_addr,
                    390:                         uint32_t metric_preference,
                    391:                         uint32_t route_metric,
                    392:                         uint32_t rpt_bit_flag)
                    393: {
                    394:   uint8_t *buf_pastend = pim_msg + buf_size;
                    395:   uint8_t *pim_msg_curr;
                    396:   int pim_msg_size;
                    397:   int remain;
                    398: 
                    399:   pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */
                    400: 
                    401:   /* Encode group */
                    402:   remain = buf_pastend - pim_msg_curr;
                    403:   pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
                    404:                                                remain,
                    405:                                                group_addr);
                    406:   if (!pim_msg_curr) {
                    407:     char group_str[100];
                    408:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
                    409:     zlog_warn("%s: failure encoding group address %s: space left=%d",
                    410:              __PRETTY_FUNCTION__, group_str, remain);
                    411:     return -1;
                    412:   }
                    413: 
                    414:   /* Encode source */
                    415:   remain = buf_pastend - pim_msg_curr;
                    416:   pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
                    417:                                                remain,
                    418:                                                source_addr);
                    419:   if (!pim_msg_curr) {
                    420:     char source_str[100];
                    421:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
                    422:     zlog_warn("%s: failure encoding source address %s: space left=%d",
                    423:              __PRETTY_FUNCTION__, source_str, remain);
                    424:     return -2;
                    425:   }
                    426: 
                    427:   /* Metric preference */
                    428:   pim_write_uint32(pim_msg_curr, rpt_bit_flag ?
                    429:                   metric_preference | 0x80000000 :
                    430:                   metric_preference);
                    431:   pim_msg_curr += 4;
                    432: 
                    433:   /* Route metric */
                    434:   pim_write_uint32(pim_msg_curr, route_metric);
                    435:   pim_msg_curr += 4;
                    436: 
                    437:   /*
                    438:     Add PIM header
                    439:   */
                    440:   pim_msg_size = pim_msg_curr - pim_msg;
                    441:   pim_msg_build_header(pim_msg, pim_msg_size,
                    442:                       PIM_MSG_TYPE_ASSERT);
                    443: 
                    444:   return pim_msg_size;
                    445: }
                    446: 
                    447: static int pim_assert_do(struct pim_ifchannel *ch,
                    448:                         struct pim_assert_metric metric)
                    449: {
                    450:   struct interface *ifp;
                    451:   struct pim_interface *pim_ifp;
                    452:   uint8_t pim_msg[1000];
                    453:   int pim_msg_size;
                    454: 
                    455:   ifp = ch->interface;
                    456:   zassert(ifp);
                    457: 
                    458:   pim_ifp = ifp->info;
                    459:   if (!pim_ifp) {
                    460:     zlog_warn("%s: pim not enabled on interface: %s",
                    461:              __PRETTY_FUNCTION__, ifp->name);
                    462:     return -1;
                    463:   }
                    464: 
                    465:   pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
                    466:                                      ch->group_addr, ch->source_addr,
                    467:                                      metric.metric_preference,
                    468:                                      metric.route_metric,
                    469:                                      metric.rpt_bit_flag);
                    470:   if (pim_msg_size < 1) {
                    471:     zlog_warn("%s: failure building PIM assert message: msg_size=%d",
                    472:              __PRETTY_FUNCTION__, pim_msg_size);
                    473:     return -2;
                    474:   }
                    475: 
                    476:   /*
                    477:     RFC 4601: 4.3.1.  Sending Hello Messages
                    478:     
                    479:     Thus, if a router needs to send a Join/Prune or Assert message on
                    480:     an interface on which it has not yet sent a Hello message with the
                    481:     currently configured IP address, then it MUST immediately send the
                    482:     relevant Hello message without waiting for the Hello Timer to
                    483:     expire, followed by the Join/Prune or Assert message.
                    484:   */
                    485:   pim_hello_require(ifp);
                    486: 
                    487:   if (PIM_DEBUG_PIM_TRACE) {
                    488:     char source_str[100];
                    489:     char group_str[100];
                    490:     pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
                    491:     pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
                    492:     zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
                    493:               __PRETTY_FUNCTION__, 
                    494:               ifp->name, source_str, group_str,
                    495:               metric.metric_preference,
                    496:               metric.route_metric,
                    497:               PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
                    498:   }
                    499: 
                    500:   if (pim_msg_send(pim_ifp->pim_sock_fd,
                    501:                   qpim_all_pim_routers_addr,
                    502:                   pim_msg,
                    503:                   pim_msg_size,
                    504:                   ifp->name)) {
                    505:     zlog_warn("%s: could not send PIM message on interface %s",
                    506:              __PRETTY_FUNCTION__, ifp->name);
                    507:     return -3;
                    508:   }
                    509: 
                    510:   return 0;
                    511: }
                    512: 
                    513: int pim_assert_send(struct pim_ifchannel *ch)
                    514: {
                    515:   return pim_assert_do(ch, ch->ifassert_my_metric);
                    516: }
                    517: 
                    518: /*
                    519:   RFC 4601: 4.6.4.  AssertCancel Messages
                    520: 
                    521:   An AssertCancel(S,G) is an infinite metric assert with the RPT bit
                    522:   set that names S as the source.
                    523:  */
                    524: static int pim_assert_cancel(struct pim_ifchannel *ch)
                    525: {
                    526:   struct pim_assert_metric metric;
                    527: 
                    528:   metric.rpt_bit_flag      = 0;
                    529:   metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
                    530:   metric.route_metric      = PIM_ASSERT_ROUTE_METRIC_MAX;
                    531:   metric.ip_address        = ch->source_addr;
                    532: 
                    533:   return pim_assert_do(ch, metric);
                    534: }
                    535: 
                    536: static int on_assert_timer(struct thread *t)
                    537: {
                    538:   struct pim_ifchannel *ch;
                    539:   struct interface *ifp;
                    540: 
                    541:   zassert(t);
                    542:   ch = THREAD_ARG(t);
                    543:   zassert(ch);
                    544: 
                    545:   ifp = ch->interface;
                    546:   zassert(ifp);
                    547: 
                    548:   if (PIM_DEBUG_PIM_TRACE) {
                    549:     char src_str[100];
                    550:     char grp_str[100];
                    551:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    552:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    553:     zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
                    554:               __PRETTY_FUNCTION__,
                    555:               src_str, grp_str, ifp->name);
                    556:   }
                    557: 
                    558:   ch->t_ifassert_timer = 0;
                    559: 
                    560:   switch (ch->ifassert_state) {
                    561:   case PIM_IFASSERT_I_AM_WINNER:
                    562:     zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
                    563:     assert_action_a3(ch);
                    564:     break;
                    565:   case PIM_IFASSERT_I_AM_LOSER:
                    566:     assert_action_a5(ch);
                    567:     break;
                    568:   default:
                    569:     {
                    570:       char source_str[100];
                    571:       char group_str[100];
                    572:       pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
                    573:       pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
                    574:       zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
                    575:                __PRETTY_FUNCTION__,
                    576:                source_str, group_str, ch->ifassert_state, ifp->name);
                    577:     }
                    578:   }
                    579: 
                    580:   return 0;
                    581: }
                    582: 
                    583: static void assert_timer_off(struct pim_ifchannel *ch)
                    584: {
                    585:   struct interface *ifp;
                    586: 
                    587:   zassert(ch);
                    588:   ifp = ch->interface;
                    589:   zassert(ifp);
                    590: 
                    591:   if (PIM_DEBUG_PIM_TRACE) {
                    592:     if (ch->t_ifassert_timer) {
                    593:       char src_str[100];
                    594:       char grp_str[100];
                    595:       pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    596:       pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    597:       zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
                    598:                 __PRETTY_FUNCTION__,
                    599:                 src_str, grp_str, ifp->name);
                    600:     }
                    601:   }
                    602:   THREAD_OFF(ch->t_ifassert_timer);
                    603:   zassert(!ch->t_ifassert_timer);
                    604: }
                    605: 
                    606: static void pim_assert_timer_set(struct pim_ifchannel *ch,
                    607:                                 int interval)
                    608: {
                    609:   struct interface *ifp;
                    610: 
                    611:   zassert(ch);
                    612:   ifp = ch->interface;
                    613:   zassert(ifp);
                    614: 
                    615:   assert_timer_off(ch);
                    616: 
                    617:   if (PIM_DEBUG_PIM_TRACE) {
                    618:     char src_str[100];
                    619:     char grp_str[100];
                    620:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    621:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    622:     zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
                    623:               __PRETTY_FUNCTION__,
                    624:               src_str, grp_str, interval, ifp->name);
                    625:   }
                    626: 
                    627:   THREAD_TIMER_ON(master, ch->t_ifassert_timer,
                    628:                  on_assert_timer,
                    629:                  ch, interval);
                    630: }
                    631: 
                    632: static void pim_assert_timer_reset(struct pim_ifchannel *ch)
                    633: {
                    634:   pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL);
                    635: }
                    636: 
                    637: /*
                    638:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    639: 
                    640:   (S,G) Assert State machine Actions
                    641: 
                    642:   A1:  Send Assert(S,G).
                    643:   Set Assert Timer to (Assert_Time - Assert_Override_Interval).
                    644:   Store self as AssertWinner(S,G,I).
                    645:   Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I).
                    646: */
                    647: int assert_action_a1(struct pim_ifchannel *ch)
                    648: {
                    649:   struct interface *ifp = ch->interface;
                    650:   struct pim_interface *pim_ifp;
                    651: 
                    652:   zassert(ifp);
                    653: 
                    654:   pim_ifp = ifp->info;
                    655:   if (!pim_ifp) {
                    656:     char src_str[100];
                    657:     char grp_str[100];
                    658:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    659:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    660:     zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
                    661:              __PRETTY_FUNCTION__,
                    662:              src_str, grp_str, ifp->name);
                    663:     return -1; /* must return since pim_ifp is used below */
                    664:   }
                    665: 
                    666:   /* Switch to I_AM_WINNER before performing action_a3 below */
                    667:   pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER,
                    668:                          pim_ifp->primary_address,
                    669:                          pim_macro_spt_assert_metric(&ch->upstream->rpf,
                    670:                                                      pim_ifp->primary_address));
                    671: 
                    672:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
                    673:   if (assert_action_a3(ch)) {
                    674:     char src_str[100];
                    675:     char grp_str[100];
                    676:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    677:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    678:     zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
                    679:              __PRETTY_FUNCTION__,
                    680:              src_str, grp_str, ifp->name);
                    681:     /* warning only */
                    682:   }
                    683: 
                    684:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
                    685: 
                    686:   return 0;
                    687: }
                    688: 
                    689: /*
                    690:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    691: 
                    692:   (S,G) Assert State machine Actions
                    693: 
                    694:      A2:  Store new assert winner as AssertWinner(S,G,I) and assert
                    695:           winner metric as AssertWinnerMetric(S,G,I).
                    696:           Set Assert Timer to Assert_Time.
                    697: */
                    698: static void assert_action_a2(struct pim_ifchannel *ch,
                    699:                             struct pim_assert_metric winner_metric)
                    700: {
                    701:   pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER,
                    702:                          winner_metric.ip_address,
                    703:                          winner_metric);
                    704:   
                    705:   pim_assert_timer_set(ch, PIM_ASSERT_TIME);
                    706: 
                    707:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
                    708: }
                    709: 
                    710: /*
                    711:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    712: 
                    713:   (S,G) Assert State machine Actions
                    714: 
                    715:   A3:  Send Assert(S,G).
                    716:   Set Assert Timer to (Assert_Time - Assert_Override_Interval).
                    717: */
                    718: static int assert_action_a3(struct pim_ifchannel *ch)
                    719: {
                    720:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
                    721: 
                    722:   pim_assert_timer_reset(ch);
                    723: 
                    724:   if (pim_assert_send(ch)) {
                    725:     char src_str[100];
                    726:     char grp_str[100];
                    727:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    728:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    729: 
                    730:     zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
                    731:              __PRETTY_FUNCTION__,
                    732:              src_str, grp_str, ch->interface->name);
                    733:     return -1;
                    734:   }
                    735: 
                    736:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
                    737: 
                    738:   return 0;
                    739: }
                    740: 
                    741: /*
                    742:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    743: 
                    744:   (S,G) Assert State machine Actions
                    745: 
                    746:      A4:  Send AssertCancel(S,G).
                    747:           Delete assert info (AssertWinner(S,G,I) and
                    748:           AssertWinnerMetric(S,G,I) will then return their default
                    749:           values).
                    750: */
                    751: void assert_action_a4(struct pim_ifchannel *ch)
                    752: {
                    753:   if (pim_assert_cancel(ch)) {
                    754:     char src_str[100];
                    755:     char grp_str[100];
                    756:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
                    757:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
                    758:     zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
                    759:              __PRETTY_FUNCTION__,
                    760:              src_str, grp_str, ch->interface->name);
                    761:     /* log warning only */
                    762:   }
                    763: 
                    764:   assert_action_a5(ch);
                    765: 
                    766:   zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
                    767: }
                    768: 
                    769: /*
                    770:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    771: 
                    772:   (S,G) Assert State machine Actions
                    773: 
                    774:   A5: Delete assert info (AssertWinner(S,G,I) and
                    775:   AssertWinnerMetric(S,G,I) will then return their default values).
                    776: */
                    777: void assert_action_a5(struct pim_ifchannel *ch)
                    778: {
                    779:   reset_ifassert_state(ch);
                    780:   zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
                    781: }
                    782: 
                    783: /*
                    784:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
                    785: 
                    786:   (S,G) Assert State machine Actions
                    787: 
                    788:      A6:  Store new assert winner as AssertWinner(S,G,I) and assert
                    789:           winner metric as AssertWinnerMetric(S,G,I).
                    790:           Set Assert Timer to Assert_Time.
                    791:           If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true)
                    792:           set SPTbit(S,G) to TRUE.
                    793: */
                    794: static void assert_action_a6(struct pim_ifchannel *ch,
                    795:                             struct pim_assert_metric winner_metric)
                    796: {
                    797:   assert_action_a2(ch, winner_metric);
                    798: 
                    799:   /*
                    800:     If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set
                    801:     SPTbit(S,G) to TRUE.
                    802:     
                    803:     Notice: For PIM SSM, SPTbit(S,G) is already always true.
                    804:   */
                    805: 
                    806:   zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
                    807: }
                    808: 

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