back to topotato report
topotato coverage report
Current view: top level - pimd - pim_macro.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 69 92 75.0 %
Date: 2023-02-24 19:38:44 Functions: 8 10 80.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 "vty.h"
      25             : #include "plist.h"
      26             : 
      27             : #include "pimd.h"
      28             : #include "pim_instance.h"
      29             : #include "pim_macro.h"
      30             : #include "pim_iface.h"
      31             : #include "pim_ifchannel.h"
      32             : #include "pim_rp.h"
      33             : 
      34             : /*
      35             :   DownstreamJPState(S,G,I) is the per-interface state machine for
      36             :   receiving (S,G) Join/Prune messages.
      37             : 
      38             :   DownstreamJPState(S,G,I) is either Join or Prune-Pending
      39             :   DownstreamJPState(*,G,I) is either Join or Prune-Pending
      40             : */
      41          97 : static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch)
      42             : {
      43          97 :         switch (ch->ifjoin_state) {
      44             :         case PIM_IFJOIN_NOINFO:
      45             :         case PIM_IFJOIN_PRUNE:
      46             :         case PIM_IFJOIN_PRUNE_TMP:
      47             :         case PIM_IFJOIN_PRUNE_PENDING_TMP:
      48             :                 return 0;
      49           0 :         case PIM_IFJOIN_JOIN:
      50             :         case PIM_IFJOIN_PRUNE_PENDING:
      51           0 :                 return 1;
      52             :         }
      53             :         return 0;
      54             : }
      55             : 
      56             : /*
      57             :   The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD
      58             :   module or other local membership mechanism has determined that local
      59             :   members on interface I desire to receive traffic sent specifically
      60             :   by S to G.
      61             : */
      62          53 : static int local_receiver_include(const struct pim_ifchannel *ch)
      63             : {
      64             :         /* local_receiver_include(S,G,I) ? */
      65          53 :         return ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE;
      66             : }
      67             : 
      68             : /*
      69             :   RFC 4601: 4.1.6.  State Summarization Macros
      70             : 
      71             :    The set "joins(S,G)" is the set of all interfaces on which the
      72             :    router has received (S,G) Joins:
      73             : 
      74             :    joins(S,G) =
      75             :        { all interfaces I such that
      76             :          DownstreamJPState(S,G,I) is either Join or Prune-Pending }
      77             : 
      78             :   DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
      79             : */
      80          97 : int pim_macro_chisin_joins(const struct pim_ifchannel *ch)
      81             : {
      82           0 :         return downstream_jpstate_isjoined(ch);
      83             : }
      84             : 
      85             : /*
      86             :   RFC 4601: 4.6.5.  Assert State Macros
      87             : 
      88             :    The set "lost_assert(S,G)" is the set of all interfaces on which the
      89             :    router has received (S,G) joins but has lost an (S,G) assert.
      90             : 
      91             :    lost_assert(S,G) =
      92             :        { all interfaces I such that
      93             :          lost_assert(S,G,I) == true }
      94             : 
      95             :      bool lost_assert(S,G,I) {
      96             :        if ( RPF_interface(S) == I ) {
      97             :           return false
      98             :        } else {
      99             :           return ( AssertWinner(S,G,I) != NULL AND
     100             :                    AssertWinner(S,G,I) != me  AND
     101             :                    (AssertWinnerMetric(S,G,I) is better
     102             :                       than spt_assert_metric(S,I) )
     103             :        }
     104             :      }
     105             : 
     106             :   AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
     107             :   packet that won an Assert.
     108             : */
     109          74 : int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
     110             : {
     111          74 :         struct interface *ifp;
     112          74 :         struct pim_interface *pim_ifp;
     113          74 :         struct pim_assert_metric spt_assert_metric;
     114             : 
     115          74 :         ifp = ch->interface;
     116          74 :         if (!ifp) {
     117           0 :                 zlog_warn("%s: (S,G)=%s: null interface", __func__, ch->sg_str);
     118           0 :                 return 0; /* false */
     119             :         }
     120             : 
     121             :         /* RPF_interface(S) == I ? */
     122          74 :         if (ch->upstream->rpf.source_nexthop.interface == ifp)
     123             :                 return 0; /* false */
     124             : 
     125          74 :         pim_ifp = ifp->info;
     126          74 :         if (!pim_ifp) {
     127           0 :                 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
     128             :                           __func__, ch->sg_str, ifp->name);
     129           0 :                 return 0; /* false */
     130             :         }
     131             : 
     132          74 :         if (pim_addr_is_any(ch->ifassert_winner))
     133             :                 return 0; /* false */
     134             : 
     135             :         /* AssertWinner(S,G,I) == me ? */
     136           0 :         if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address))
     137             :                 return 0; /* false */
     138             : 
     139           0 :         spt_assert_metric = pim_macro_spt_assert_metric(
     140           0 :                 &ch->upstream->rpf, pim_ifp->primary_address);
     141             : 
     142           0 :         return pim_assert_metric_better(&ch->ifassert_winner_metric,
     143             :                                         &spt_assert_metric);
     144             : }
     145             : 
     146             : /*
     147             :   RFC 4601: 4.1.6.  State Summarization Macros
     148             : 
     149             :    pim_include(S,G) =
     150             :        { all interfaces I such that:
     151             :          ( (I_am_DR( I ) AND lost_assert(S,G,I) == false )
     152             :            OR AssertWinner(S,G,I) == me )
     153             :           AND  local_receiver_include(S,G,I) }
     154             : 
     155             :    AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
     156             :    packet that won an Assert.
     157             : */
     158          30 : int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch)
     159             : {
     160          30 :         struct pim_interface *pim_ifp = ch->interface->info;
     161          30 :         bool mlag_active = false;
     162             : 
     163          30 :         if (!pim_ifp) {
     164           0 :                 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
     165             :                           __func__, ch->sg_str, ch->interface->name);
     166           0 :                 return 0; /* false */
     167             :         }
     168             : 
     169             :         /* local_receiver_include(S,G,I) ? */
     170          30 :         if (!local_receiver_include(ch))
     171             :                 return 0; /* false */
     172             : 
     173             :         /* OR AssertWinner(S,G,I) == me ? */
     174          15 :         if (!pim_addr_cmp(ch->ifassert_winner, pim_ifp->primary_address))
     175             :                 return 1; /* true */
     176             : 
     177             :         /*
     178             :          * When we have a activeactive interface we need to signal
     179             :          * that this interface is interesting to the upstream
     180             :          * decision to JOIN *if* we are syncing over the interface
     181             :          */
     182          15 :         if (pim_ifp->activeactive) {
     183           0 :                 struct pim_upstream *up = ch->upstream;
     184             : 
     185           0 :                 if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
     186          15 :                         mlag_active = true;
     187             :         }
     188             : 
     189          15 :         return (
     190             :                 /* I_am_DR( I ) ? */
     191          30 :                 (PIM_I_am_DR(pim_ifp) || mlag_active) &&
     192             :                 /* lost_assert(S,G,I) == false ? */
     193          15 :                 (!pim_macro_ch_lost_assert(ch)));
     194             : }
     195             : 
     196          64 : int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch)
     197             : {
     198          64 :         if (pim_macro_chisin_joins(ch))
     199             :                 return 1; /* true */
     200             : 
     201          30 :         return pim_macro_chisin_pim_include(ch);
     202             : }
     203             : 
     204             : /*
     205             :   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
     206             : 
     207             :   CouldAssert(S,G,I) =
     208             :   SPTbit(S,G)==TRUE
     209             :   AND (RPF_interface(S) != I)
     210             :   AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
     211             :                  (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
     212             :                  (-) lost_assert(*,G)
     213             :                  (+) joins(S,G) (+) pim_include(S,G) ) )
     214             : 
     215             :   CouldAssert(S,G,I) is true for downstream interfaces that would be in
     216             :   the inherited_olist(S,G) if (S,G) assert information was not taken
     217             :   into account.
     218             : 
     219             :   CouldAssert(S,G,I) may be affected by changes in the following:
     220             : 
     221             :   pim_ifp->primary_address
     222             :   pim_ifp->pim_dr_addr
     223             :   ch->ifassert_winner_metric
     224             :   ch->ifassert_winner
     225             :   ch->local_ifmembership
     226             :   ch->ifjoin_state
     227             :   ch->upstream->rpf.source_nexthop.mrib_metric_preference
     228             :   ch->upstream->rpf.source_nexthop.mrib_route_metric
     229             :   ch->upstream->rpf.source_nexthop.interface
     230             : */
     231          27 : int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch)
     232             : {
     233          27 :         struct interface *ifp;
     234             : 
     235          27 :         ifp = ch->interface;
     236          27 :         if (!ifp) {
     237           0 :                 zlog_warn("%s: (S,G)=%s: null interface", __func__, ch->sg_str);
     238           0 :                 return 0; /* false */
     239             :         }
     240             : 
     241             :         /* SPTbit(S,G) == true */
     242          27 :         if (ch->upstream->sptbit == PIM_UPSTREAM_SPTBIT_FALSE)
     243             :                 return 0; /* false */
     244             : 
     245             :         /* RPF_interface(S) != I ? */
     246           5 :         if (ch->upstream->rpf.source_nexthop.interface == ifp)
     247             :                 return 0; /* false */
     248             : 
     249             :         /* I in joins(S,G) (+) pim_include(S,G) ? */
     250           5 :         return pim_macro_chisin_joins_or_include(ch);
     251             : }
     252             : 
     253             : /*
     254             :   RFC 4601: 4.6.3.  Assert Metrics
     255             : 
     256             :    spt_assert_metric(S,I) gives the assert metric we use if we're
     257             :    sending an assert based on active (S,G) forwarding state:
     258             : 
     259             :     assert_metric
     260             :     spt_assert_metric(S,I) {
     261             :       return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)}
     262             :     }
     263             : */
     264           4 : struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf,
     265             :                                                      pim_addr ifaddr)
     266             : {
     267           4 :         struct pim_assert_metric metric;
     268             : 
     269           4 :         metric.rpt_bit_flag = 0;
     270           4 :         metric.metric_preference = rpf->source_nexthop.mrib_metric_preference;
     271           4 :         metric.route_metric = rpf->source_nexthop.mrib_route_metric;
     272           4 :         metric.ip_address = ifaddr;
     273             : 
     274           0 :         return metric;
     275             : }
     276             : 
     277             : /*
     278             :   RFC 4601: 4.6.3.  Assert Metrics
     279             : 
     280             :    An assert metric for (S,G) to include in (or compare against) an
     281             :    Assert message sent on interface I should be computed using the
     282             :    following pseudocode:
     283             : 
     284             :   assert_metric  my_assert_metric(S,G,I) {
     285             :     if( CouldAssert(S,G,I) == true ) {
     286             :       return spt_assert_metric(S,I)
     287             :     } else if( CouldAssert(*,G,I) == true ) {
     288             :       return rpt_assert_metric(G,I)
     289             :     } else {
     290             :       return infinite_assert_metric()
     291             :     }
     292             :   }
     293             : */
     294             : struct pim_assert_metric
     295          28 : pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch)
     296             : {
     297          28 :         struct pim_interface *pim_ifp;
     298             : 
     299          28 :         pim_ifp = ch->interface->info;
     300             : 
     301          28 :         if (pim_ifp) {
     302          28 :                 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
     303           4 :                         return pim_macro_spt_assert_metric(
     304           4 :                                 &ch->upstream->rpf, pim_ifp->primary_address);
     305             :                 }
     306             :         }
     307             : 
     308          24 :         return router->infinite_assert_metric;
     309             : }
     310             : 
     311             : /*
     312             :   RFC 4601 4.2.  Data Packet Forwarding Rules
     313             : 
     314             :   Macro:
     315             :   inherited_olist(S,G) =
     316             :     inherited_olist(S,G,rpt) (+)
     317             :     joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
     318             : */
     319           5 : static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch)
     320             : {
     321           5 :         if (pim_macro_ch_lost_assert(ch))
     322             :                 return 0; /* false */
     323             : 
     324           5 :         return pim_macro_chisin_joins_or_include(ch);
     325             : }
     326             : 
     327             : /*
     328             :   RFC 4601 4.2.  Data Packet Forwarding Rules
     329             :   RFC 4601 4.8.2.  PIM-SSM-Only Routers
     330             : 
     331             :   Additionally, the Packet forwarding rules of Section 4.2 can be
     332             :   simplified in a PIM-SSM-only router:
     333             : 
     334             :   iif is the incoming interface of the packet.
     335             :   oiflist = NULL
     336             :   if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
     337             :     oiflist = inherited_olist(S,G)
     338             :   } else if (iif is in inherited_olist(S,G)) {
     339             :     send Assert(S,G) on iif
     340             :   }
     341             :   oiflist = oiflist (-) iif
     342             :   forward packet on all interfaces in oiflist
     343             : 
     344             :   Macro:
     345             :   inherited_olist(S,G) =
     346             :     joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
     347             : 
     348             :   Note:
     349             :   - The following test is performed as response to WRONGVIF kernel
     350             :     upcall:
     351             :     if (iif is in inherited_olist(S,G)) {
     352             :       send Assert(S,G) on iif
     353             :     }
     354             :     See pim_mroute.c mroute_msg().
     355             : */
     356           5 : int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch)
     357             : {
     358           5 :         if (ch->upstream->join_state == PIM_UPSTREAM_NOTJOINED) {
     359             :                 /* oiflist is NULL */
     360             :                 return 0; /* false */
     361             :         }
     362             : 
     363             :         /* oiflist = oiflist (-) iif */
     364           5 :         if (ch->interface == ch->upstream->rpf.source_nexthop.interface)
     365             :                 return 0; /* false */
     366             : 
     367           5 :         return pim_macro_chisin_inherited_olist(ch);
     368             : }
     369             : 
     370             : /*
     371             :   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
     372             : 
     373             :   AssertTrackingDesired(S,G,I) =
     374             :   (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
     375             :         (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
     376             :         (-) lost_assert(*,G)
     377             :         (+) joins(S,G) ) )
     378             :      OR (local_receiver_include(S,G,I) == true
     379             :          AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me)))
     380             :      OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == true))
     381             :      OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == true)
     382             :          AND (SPTbit(S,G) == false))
     383             : 
     384             :   AssertTrackingDesired(S,G,I) is true on any interface in which an
     385             :   (S,G) assert might affect our behavior.
     386             : */
     387          33 : int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch)
     388             : {
     389          33 :         struct pim_interface *pim_ifp;
     390          33 :         struct interface *ifp;
     391             : 
     392          33 :         ifp = ch->interface;
     393          33 :         if (!ifp) {
     394           0 :                 zlog_warn("%s: (S,G)=%s: null interface", __func__, ch->sg_str);
     395           0 :                 return 0; /* false */
     396             :         }
     397             : 
     398          33 :         pim_ifp = ifp->info;
     399          33 :         if (!pim_ifp) {
     400           0 :                 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
     401             :                           __func__, ch->sg_str, ch->interface->name);
     402           0 :                 return 0; /* false */
     403             :         }
     404             : 
     405             :         /* I in joins(S,G) ? */
     406          42 :         if (pim_macro_chisin_joins(ch))
     407             :                 return 1; /* true */
     408             : 
     409             :         /* local_receiver_include(S,G,I) ? */
     410          23 :         if (local_receiver_include(ch)) {
     411             :                 /* I_am_DR(I) ? */
     412           9 :                 if (PIM_I_am_DR(pim_ifp))
     413             :                         return 1; /* true */
     414             : 
     415             :                 /* AssertWinner(S,G,I) == me ? */
     416           0 :                 if (!pim_addr_cmp(ch->ifassert_winner,
     417             :                                   pim_ifp->primary_address))
     418             :                         return 1; /* true */
     419             :         }
     420             : 
     421             :         /* RPF_interface(S) == I ? */
     422          14 :         if (ch->upstream->rpf.source_nexthop.interface == ifp) {
     423             :                 /* JoinDesired(S,G) ? */
     424           1 :                 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags))
     425             :                         return 1; /* true */
     426             :         }
     427             : 
     428             :         return 0; /* false */
     429             : }

Generated by: LCOV version v1.16-topotato