Annotation of embedaddon/quagga/pimd/pim_macro.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   PIM for Quagga
        !             3:   Copyright (C) 2008  Everton da Silva Marques
        !             4: 
        !             5:   This program is free software; you can redistribute it and/or modify
        !             6:   it under the terms of the GNU General Public License as published by
        !             7:   the Free Software Foundation; either version 2 of the License, or
        !             8:   (at your option) any later version.
        !             9: 
        !            10:   This program is distributed in the hope that it will be useful, but
        !            11:   WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            13:   General Public License for more details.
        !            14:   
        !            15:   You should have received a copy of the GNU General Public License
        !            16:   along with this program; see the file COPYING; if not, write to the
        !            17:   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
        !            18:   MA 02110-1301 USA
        !            19:   
        !            20:   $QuaggaId: $Format:%an, %ai, %h$ $
        !            21: */
        !            22: 
        !            23: #include <zebra.h>
        !            24: 
        !            25: #include "log.h"
        !            26: 
        !            27: #include "pim_macro.h"
        !            28: #include "pimd.h"
        !            29: #include "pim_str.h"
        !            30: #include "pim_iface.h"
        !            31: #include "pim_ifchannel.h"
        !            32: 
        !            33: #define PIM_IFP_I_am_DR(pim_ifp) ((pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr)
        !            34: 
        !            35: /*
        !            36:   DownstreamJPState(S,G,I) is the per-interface state machine for
        !            37:   receiving (S,G) Join/Prune messages.
        !            38: 
        !            39:   DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
        !            40: */
        !            41: static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch)
        !            42: {
        !            43:   return ch->ifjoin_state != PIM_IFJOIN_NOINFO;
        !            44: }
        !            45: 
        !            46: /*
        !            47:   The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD
        !            48:   module or other local membership mechanism has determined that local
        !            49:   members on interface I desire to receive traffic sent specifically
        !            50:   by S to G.
        !            51: */
        !            52: static int local_receiver_include(const struct pim_ifchannel *ch)
        !            53: {
        !            54:   /* local_receiver_include(S,G,I) ? */
        !            55:   return ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE;
        !            56: }
        !            57: 
        !            58: /*
        !            59:   RFC 4601: 4.1.6.  State Summarization Macros
        !            60: 
        !            61:    The set "joins(S,G)" is the set of all interfaces on which the
        !            62:    router has received (S,G) Joins:
        !            63: 
        !            64:    joins(S,G) =
        !            65:        { all interfaces I such that
        !            66:          DownstreamJPState(S,G,I) is either Join or Prune-Pending }
        !            67: 
        !            68:   DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
        !            69: */
        !            70: int pim_macro_chisin_joins(const struct pim_ifchannel *ch)
        !            71: {
        !            72:   return downstream_jpstate_isjoined(ch);
        !            73: }
        !            74: 
        !            75: /*
        !            76:   RFC 4601: 4.6.5.  Assert State Macros
        !            77: 
        !            78:    The set "lost_assert(S,G)" is the set of all interfaces on which the
        !            79:    router has received (S,G) joins but has lost an (S,G) assert.
        !            80: 
        !            81:    lost_assert(S,G) =
        !            82:        { all interfaces I such that
        !            83:          lost_assert(S,G,I) == TRUE }
        !            84: 
        !            85:      bool lost_assert(S,G,I) {
        !            86:        if ( RPF_interface(S) == I ) {
        !            87:           return FALSE
        !            88:        } else {
        !            89:           return ( AssertWinner(S,G,I) != NULL AND
        !            90:                    AssertWinner(S,G,I) != me  AND
        !            91:                    (AssertWinnerMetric(S,G,I) is better
        !            92:                       than spt_assert_metric(S,I) )
        !            93:        }
        !            94:      }
        !            95: 
        !            96:   AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
        !            97:   packet that won an Assert.
        !            98: */
        !            99: int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
        !           100: {
        !           101:   struct interface *ifp;
        !           102:   struct pim_interface *pim_ifp;
        !           103:   struct pim_assert_metric spt_assert_metric;
        !           104: 
        !           105:   ifp = ch->interface;
        !           106:   if (!ifp) {
        !           107:     char src_str[100];
        !           108:     char grp_str[100];
        !           109:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           110:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           111:     zlog_warn("%s: (S,G)=(%s,%s): null interface",
        !           112:              __PRETTY_FUNCTION__,
        !           113:              src_str, grp_str);
        !           114:     return 0; /* false */
        !           115:   }
        !           116: 
        !           117:   /* RPF_interface(S) == I ? */
        !           118:   if (ch->upstream->rpf.source_nexthop.interface == ifp)
        !           119:     return 0; /* false */
        !           120: 
        !           121:   pim_ifp = ifp->info;
        !           122:   if (!pim_ifp) {
        !           123:     char src_str[100];
        !           124:     char grp_str[100];
        !           125:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           126:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           127:     zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
        !           128:              __PRETTY_FUNCTION__,
        !           129:              src_str, grp_str, ifp->name);
        !           130:     return 0; /* false */
        !           131:   }
        !           132: 
        !           133:   if (PIM_INADDR_IS_ANY(ch->ifassert_winner))
        !           134:     return 0; /* false */
        !           135: 
        !           136:   /* AssertWinner(S,G,I) == me ? */
        !           137:   if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr)
        !           138:     return 0; /* false */
        !           139: 
        !           140:   spt_assert_metric = pim_macro_spt_assert_metric(&ch->upstream->rpf,
        !           141:                                                  pim_ifp->primary_address);
        !           142: 
        !           143:   return pim_assert_metric_better(&ch->ifassert_winner_metric,
        !           144:                                  &spt_assert_metric);
        !           145: }
        !           146: 
        !           147: /*
        !           148:   RFC 4601: 4.1.6.  State Summarization Macros
        !           149: 
        !           150:    pim_include(S,G) =
        !           151:        { all interfaces I such that:
        !           152:          ( (I_am_DR( I ) AND lost_assert(S,G,I) == FALSE )
        !           153:            OR AssertWinner(S,G,I) == me )
        !           154:           AND  local_receiver_include(S,G,I) }
        !           155: 
        !           156:    AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
        !           157:    packet that won an Assert.
        !           158: */
        !           159: int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch)
        !           160: {
        !           161:   struct pim_interface *pim_ifp = ch->interface->info;
        !           162: 
        !           163:   if (!pim_ifp) {
        !           164:     char src_str[100];
        !           165:     char grp_str[100];
        !           166:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           167:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           168:     zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
        !           169:              __PRETTY_FUNCTION__,
        !           170:              src_str, grp_str, ch->interface->name);
        !           171:     return 0; /* false */
        !           172:   }
        !           173: 
        !           174:   /* local_receiver_include(S,G,I) ? */
        !           175:   if (!local_receiver_include(ch))
        !           176:     return 0; /* false */
        !           177:     
        !           178:   /* OR AssertWinner(S,G,I) == me ? */
        !           179:   if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr)
        !           180:     return 1; /* true */
        !           181:     
        !           182:   return (
        !           183:          /* I_am_DR( I ) ? */
        !           184:          PIM_IFP_I_am_DR(pim_ifp)
        !           185:          &&
        !           186:          /* lost_assert(S,G,I) == FALSE ? */
        !           187:          (!pim_macro_ch_lost_assert(ch))
        !           188:          );
        !           189: }
        !           190: 
        !           191: int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch)
        !           192: {
        !           193:   if (pim_macro_chisin_joins(ch))
        !           194:     return 1; /* true */
        !           195: 
        !           196:   return pim_macro_chisin_pim_include(ch);
        !           197: }
        !           198: 
        !           199: /*
        !           200:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
        !           201: 
        !           202:   CouldAssert(S,G,I) =
        !           203:   SPTbit(S,G)==TRUE
        !           204:   AND (RPF_interface(S) != I)
        !           205:   AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
        !           206:                  (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
        !           207:                  (-) lost_assert(*,G)
        !           208:                  (+) joins(S,G) (+) pim_include(S,G) ) )
        !           209: 
        !           210:   CouldAssert(S,G,I) is true for downstream interfaces that would be in
        !           211:   the inherited_olist(S,G) if (S,G) assert information was not taken
        !           212:   into account.
        !           213: 
        !           214:   CouldAssert(S,G,I) may be affected by changes in the following:
        !           215: 
        !           216:   pim_ifp->primary_address
        !           217:   pim_ifp->pim_dr_addr
        !           218:   ch->ifassert_winner_metric
        !           219:   ch->ifassert_winner
        !           220:   ch->local_ifmembership
        !           221:   ch->ifjoin_state
        !           222:   ch->upstream->rpf.source_nexthop.mrib_metric_preference
        !           223:   ch->upstream->rpf.source_nexthop.mrib_route_metric
        !           224:   ch->upstream->rpf.source_nexthop.interface
        !           225: */
        !           226: int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch)
        !           227: {
        !           228:   struct interface *ifp;
        !           229: 
        !           230:   /* SPTbit(S,G) is always true for PIM-SSM-Only Routers */
        !           231: 
        !           232:   ifp = ch->interface;
        !           233:   if (!ifp) {
        !           234:     char src_str[100];
        !           235:     char grp_str[100];
        !           236:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           237:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           238:     zlog_warn("%s: (S,G)=(%s,%s): null interface",
        !           239:              __PRETTY_FUNCTION__,
        !           240:              src_str, grp_str);
        !           241:     return 0; /* false */
        !           242:   }
        !           243: 
        !           244:   /* RPF_interface(S) != I ? */
        !           245:   if (ch->upstream->rpf.source_nexthop.interface == ifp)
        !           246:     return 0; /* false */
        !           247: 
        !           248:   /* I in joins(S,G) (+) pim_include(S,G) ? */
        !           249:   return pim_macro_chisin_joins_or_include(ch);
        !           250: }
        !           251: 
        !           252: /*
        !           253:   RFC 4601: 4.6.3.  Assert Metrics
        !           254: 
        !           255:    spt_assert_metric(S,I) gives the assert metric we use if we're
        !           256:    sending an assert based on active (S,G) forwarding state:
        !           257: 
        !           258:     assert_metric
        !           259:     spt_assert_metric(S,I) {
        !           260:       return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)}
        !           261:     }
        !           262: */
        !           263: struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf,
        !           264:                                                     struct in_addr ifaddr)
        !           265: {
        !           266:   struct pim_assert_metric metric;
        !           267: 
        !           268:   metric.rpt_bit_flag      = 0;
        !           269:   metric.metric_preference = rpf->source_nexthop.mrib_metric_preference;
        !           270:   metric.route_metric      = rpf->source_nexthop.mrib_route_metric;
        !           271:   metric.ip_address        = ifaddr;
        !           272: 
        !           273:   return metric;
        !           274: }
        !           275: 
        !           276: /*
        !           277:   RFC 4601: 4.6.3.  Assert Metrics
        !           278: 
        !           279:    An assert metric for (S,G) to include in (or compare against) an
        !           280:    Assert message sent on interface I should be computed using the
        !           281:    following pseudocode:
        !           282: 
        !           283:   assert_metric  my_assert_metric(S,G,I) {
        !           284:     if( CouldAssert(S,G,I) == TRUE ) {
        !           285:       return spt_assert_metric(S,I)
        !           286:     } else if( CouldAssert(*,G,I) == TRUE ) {
        !           287:       return rpt_assert_metric(G,I)
        !           288:     } else {
        !           289:       return infinite_assert_metric()
        !           290:     }
        !           291:   }
        !           292: */
        !           293: struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch)
        !           294: {
        !           295:   struct pim_interface *pim_ifp;
        !           296: 
        !           297:   pim_ifp = ch->interface->info;
        !           298: 
        !           299:   if (pim_ifp) {
        !           300:     if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
        !           301:       return pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address);
        !           302:     }
        !           303:   }
        !           304: 
        !           305:   return qpim_infinite_assert_metric;
        !           306: }
        !           307: 
        !           308: /*
        !           309:   RFC 4601 4.2.  Data Packet Forwarding Rules
        !           310:   RFC 4601 4.8.2.  PIM-SSM-Only Routers
        !           311:   
        !           312:   Macro:
        !           313:   inherited_olist(S,G) =
        !           314:     joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
        !           315: */
        !           316: static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch)
        !           317: {
        !           318:   if (pim_macro_ch_lost_assert(ch))
        !           319:     return 0; /* false */
        !           320: 
        !           321:   return pim_macro_chisin_joins_or_include(ch);
        !           322: }
        !           323: 
        !           324: /*
        !           325:   RFC 4601 4.2.  Data Packet Forwarding Rules
        !           326:   RFC 4601 4.8.2.  PIM-SSM-Only Routers
        !           327: 
        !           328:   Additionally, the Packet forwarding rules of Section 4.2 can be
        !           329:   simplified in a PIM-SSM-only router:
        !           330:   
        !           331:   iif is the incoming interface of the packet.
        !           332:   oiflist = NULL
        !           333:   if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
        !           334:     oiflist = inherited_olist(S,G)
        !           335:   } else if (iif is in inherited_olist(S,G)) {
        !           336:     send Assert(S,G) on iif
        !           337:   }
        !           338:   oiflist = oiflist (-) iif
        !           339:   forward packet on all interfaces in oiflist
        !           340:   
        !           341:   Macro:
        !           342:   inherited_olist(S,G) =
        !           343:     joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
        !           344: 
        !           345:   Note:
        !           346:   - The following test is performed as response to WRONGVIF kernel
        !           347:     upcall:
        !           348:     if (iif is in inherited_olist(S,G)) {
        !           349:       send Assert(S,G) on iif
        !           350:     }
        !           351:     See pim_mroute.c mroute_msg().
        !           352: */
        !           353: int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch)
        !           354: {
        !           355:   if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) {
        !           356:     /* oiflist is NULL */
        !           357:     return 0; /* false */
        !           358:   }
        !           359: 
        !           360:   /* oiflist = oiflist (-) iif */
        !           361:   if (ch->interface == ch->upstream->rpf.source_nexthop.interface)
        !           362:     return 0; /* false */
        !           363: 
        !           364:   return pim_macro_chisin_inherited_olist(ch);
        !           365: }
        !           366: 
        !           367: /*
        !           368:   RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
        !           369: 
        !           370:   AssertTrackingDesired(S,G,I) =
        !           371:   (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
        !           372:        (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
        !           373:        (-) lost_assert(*,G)
        !           374:        (+) joins(S,G) ) )
        !           375:      OR (local_receiver_include(S,G,I) == TRUE
        !           376:         AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me)))
        !           377:      OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == TRUE))
        !           378:      OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == TRUE)
        !           379:         AND (SPTbit(S,G) == FALSE))
        !           380: 
        !           381:   AssertTrackingDesired(S,G,I) is true on any interface in which an
        !           382:   (S,G) assert might affect our behavior.
        !           383: */
        !           384: int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch)
        !           385: {
        !           386:   struct pim_interface *pim_ifp;
        !           387:   struct interface *ifp;
        !           388: 
        !           389:   ifp = ch->interface;
        !           390:   if (!ifp) {
        !           391:     char src_str[100];
        !           392:     char grp_str[100];
        !           393:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           394:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           395:     zlog_warn("%s: (S,G)=(%s,%s): null interface",
        !           396:              __PRETTY_FUNCTION__,
        !           397:              src_str, grp_str);
        !           398:     return 0; /* false */
        !           399:   }
        !           400: 
        !           401:   pim_ifp = ifp->info;
        !           402:   if (!pim_ifp) {
        !           403:     char src_str[100];
        !           404:     char grp_str[100];
        !           405:     pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
        !           406:     pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
        !           407:     zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
        !           408:              __PRETTY_FUNCTION__,
        !           409:              src_str, grp_str, ch->interface->name);
        !           410:     return 0; /* false */
        !           411:   }
        !           412: 
        !           413:   /* I in joins(S,G) ? */
        !           414:   if (pim_macro_chisin_joins(ch))
        !           415:     return 1; /* true */
        !           416: 
        !           417:   /* local_receiver_include(S,G,I) ? */
        !           418:   if (local_receiver_include(ch)) {
        !           419:     /* I_am_DR(I) ? */
        !           420:     if (PIM_IFP_I_am_DR(pim_ifp))
        !           421:       return 1; /* true */
        !           422: 
        !           423:     /* AssertWinner(S,G,I) == me ? */
        !           424:     if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr)
        !           425:       return 1; /* true */
        !           426:   }
        !           427: 
        !           428:   /* RPF_interface(S) == I ? */
        !           429:   if (ch->upstream->rpf.source_nexthop.interface == ifp) {
        !           430:     /* JoinDesired(S,G) ? */
        !           431:     if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags))
        !           432:       return 1; /* true */
        !           433:   }
        !           434: 
        !           435:   return 0; /* false */
        !           436: }
        !           437: 

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