File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_macro.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>