back to topotato report
topotato coverage report
Current view: top level - pimd - pim_assert.c (source / functions) Hit Total Coverage
Test: test_pim_basic2.py::PIMTopo2Test Lines: 0 290 0.0 %
Date: 2023-02-24 18:39:36 Functions: 0 20 0.0 %

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

Generated by: LCOV version v1.16-topotato