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>