Annotation of embedaddon/quagga/pimd/pim_macro.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: 
                     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>