3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
29 #include "pim_macro.h"
30 #include "pim_iface.h"
31 #include "pim_ifchannel.h"
35 DownstreamJPState(S,G,I) is the per-interface state machine for
36 receiving (S,G) Join/Prune messages.
38 DownstreamJPState(S,G,I) is either Join or Prune-Pending
39 DownstreamJPState(*,G,I) is either Join or Prune-Pending
41 static int downstream_jpstate_isjoined(const struct pim_ifchannel
*ch
)
43 switch (ch
->ifjoin_state
)
45 case PIM_IFJOIN_NOINFO
:
46 case PIM_IFJOIN_PRUNE
:
47 case PIM_IFJOIN_PRUNE_TMP
:
48 case PIM_IFJOIN_PRUNE_PENDING_TMP
:
52 case PIM_IFJOIN_PRUNE_PENDING
:
60 The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD
61 module or other local membership mechanism has determined that local
62 members on interface I desire to receive traffic sent specifically
65 static int local_receiver_include(const struct pim_ifchannel
*ch
)
67 /* local_receiver_include(S,G,I) ? */
68 return ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
;
72 RFC 4601: 4.1.6. State Summarization Macros
74 The set "joins(S,G)" is the set of all interfaces on which the
75 router has received (S,G) Joins:
78 { all interfaces I such that
79 DownstreamJPState(S,G,I) is either Join or Prune-Pending }
81 DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
83 int pim_macro_chisin_joins(const struct pim_ifchannel
*ch
)
85 return downstream_jpstate_isjoined(ch
);
89 RFC 4601: 4.6.5. Assert State Macros
91 The set "lost_assert(S,G)" is the set of all interfaces on which the
92 router has received (S,G) joins but has lost an (S,G) assert.
95 { all interfaces I such that
96 lost_assert(S,G,I) == TRUE }
98 bool lost_assert(S,G,I) {
99 if ( RPF_interface(S) == I ) {
102 return ( AssertWinner(S,G,I) != NULL AND
103 AssertWinner(S,G,I) != me AND
104 (AssertWinnerMetric(S,G,I) is better
105 than spt_assert_metric(S,I) )
109 AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
110 packet that won an Assert.
112 int pim_macro_ch_lost_assert(const struct pim_ifchannel
*ch
)
114 struct interface
*ifp
;
115 struct pim_interface
*pim_ifp
;
116 struct pim_assert_metric spt_assert_metric
;
120 zlog_warn("%s: (S,G)=%s: null interface",
123 return 0; /* false */
126 /* RPF_interface(S) == I ? */
127 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
)
128 return 0; /* false */
132 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
134 ch
->sg_str
, ifp
->name
);
135 return 0; /* false */
138 if (PIM_INADDR_IS_ANY(ch
->ifassert_winner
))
139 return 0; /* false */
141 /* AssertWinner(S,G,I) == me ? */
142 if (ch
->ifassert_winner
.s_addr
== pim_ifp
->primary_address
.s_addr
)
143 return 0; /* false */
145 spt_assert_metric
= pim_macro_spt_assert_metric(&ch
->upstream
->rpf
,
146 pim_ifp
->primary_address
);
148 return pim_assert_metric_better(&ch
->ifassert_winner_metric
,
153 RFC 4601: 4.1.6. State Summarization Macros
156 { all interfaces I such that:
157 ( (I_am_DR( I ) AND lost_assert(S,G,I) == FALSE )
158 OR AssertWinner(S,G,I) == me )
159 AND local_receiver_include(S,G,I) }
161 AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
162 packet that won an Assert.
164 int pim_macro_chisin_pim_include(const struct pim_ifchannel
*ch
)
166 struct pim_interface
*pim_ifp
= ch
->interface
->info
;
169 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
171 ch
->sg_str
, ch
->interface
->name
);
172 return 0; /* false */
175 /* local_receiver_include(S,G,I) ? */
176 if (!local_receiver_include(ch
))
177 return 0; /* false */
179 /* OR AssertWinner(S,G,I) == me ? */
180 if (ch
->ifassert_winner
.s_addr
== pim_ifp
->primary_address
.s_addr
)
187 /* lost_assert(S,G,I) == FALSE ? */
188 (!pim_macro_ch_lost_assert(ch
))
192 int pim_macro_chisin_joins_or_include(const struct pim_ifchannel
*ch
)
194 if (pim_macro_chisin_joins(ch
))
197 return pim_macro_chisin_pim_include(ch
);
201 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
205 AND (RPF_interface(S) != I)
206 AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
207 (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
209 (+) joins(S,G) (+) pim_include(S,G) ) )
211 CouldAssert(S,G,I) is true for downstream interfaces that would be in
212 the inherited_olist(S,G) if (S,G) assert information was not taken
215 CouldAssert(S,G,I) may be affected by changes in the following:
217 pim_ifp->primary_address
219 ch->ifassert_winner_metric
221 ch->local_ifmembership
223 ch->upstream->rpf.source_nexthop.mrib_metric_preference
224 ch->upstream->rpf.source_nexthop.mrib_route_metric
225 ch->upstream->rpf.source_nexthop.interface
227 int pim_macro_ch_could_assert_eval(const struct pim_ifchannel
*ch
)
229 struct interface
*ifp
;
233 zlog_warn("%s: (S,G)=%s: null interface",
234 __PRETTY_FUNCTION__
, ch
->sg_str
);
235 return 0; /* false */
238 /* SPTbit(S,G) == TRUE */
239 if (ch
->upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_FALSE
)
240 return 0; /* false */
242 /* RPF_interface(S) != I ? */
243 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
)
244 return 0; /* false */
246 /* I in joins(S,G) (+) pim_include(S,G) ? */
247 return pim_macro_chisin_joins_or_include(ch
);
251 RFC 4601: 4.6.3. Assert Metrics
253 spt_assert_metric(S,I) gives the assert metric we use if we're
254 sending an assert based on active (S,G) forwarding state:
257 spt_assert_metric(S,I) {
258 return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)}
261 struct pim_assert_metric
pim_macro_spt_assert_metric(const struct pim_rpf
*rpf
,
262 struct in_addr ifaddr
)
264 struct pim_assert_metric metric
;
266 metric
.rpt_bit_flag
= 0;
267 metric
.metric_preference
= rpf
->source_nexthop
.mrib_metric_preference
;
268 metric
.route_metric
= rpf
->source_nexthop
.mrib_route_metric
;
269 metric
.ip_address
= ifaddr
;
275 RFC 4601: 4.6.3. Assert Metrics
277 An assert metric for (S,G) to include in (or compare against) an
278 Assert message sent on interface I should be computed using the
279 following pseudocode:
281 assert_metric my_assert_metric(S,G,I) {
282 if( CouldAssert(S,G,I) == TRUE ) {
283 return spt_assert_metric(S,I)
284 } else if( CouldAssert(*,G,I) == TRUE ) {
285 return rpt_assert_metric(G,I)
287 return infinite_assert_metric()
291 struct pim_assert_metric
pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel
*ch
)
293 struct pim_interface
*pim_ifp
;
295 pim_ifp
= ch
->interface
->info
;
298 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
299 return pim_macro_spt_assert_metric(&ch
->upstream
->rpf
, pim_ifp
->primary_address
);
303 return qpim_infinite_assert_metric
;
307 RFC 4601 4.2. Data Packet Forwarding Rules
310 inherited_olist(S,G) =
311 inherited_olist(S,G,rpt) (+)
312 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
314 static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel
*ch
)
316 if (pim_macro_ch_lost_assert(ch
))
317 return 0; /* false */
319 return pim_macro_chisin_joins_or_include(ch
);
323 RFC 4601 4.2. Data Packet Forwarding Rules
324 RFC 4601 4.8.2. PIM-SSM-Only Routers
326 Additionally, the Packet forwarding rules of Section 4.2 can be
327 simplified in a PIM-SSM-only router:
329 iif is the incoming interface of the packet.
331 if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
332 oiflist = inherited_olist(S,G)
333 } else if (iif is in inherited_olist(S,G)) {
334 send Assert(S,G) on iif
336 oiflist = oiflist (-) iif
337 forward packet on all interfaces in oiflist
340 inherited_olist(S,G) =
341 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
344 - The following test is performed as response to WRONGVIF kernel
346 if (iif is in inherited_olist(S,G)) {
347 send Assert(S,G) on iif
349 See pim_mroute.c mroute_msg().
351 int pim_macro_chisin_oiflist(const struct pim_ifchannel
*ch
)
353 if (ch
->upstream
->join_state
== PIM_UPSTREAM_NOTJOINED
) {
354 /* oiflist is NULL */
355 return 0; /* false */
358 /* oiflist = oiflist (-) iif */
359 if (ch
->interface
== ch
->upstream
->rpf
.source_nexthop
.interface
)
360 return 0; /* false */
362 return pim_macro_chisin_inherited_olist(ch
);
366 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
368 AssertTrackingDesired(S,G,I) =
369 (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
370 (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
373 OR (local_receiver_include(S,G,I) == TRUE
374 AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me)))
375 OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == TRUE))
376 OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == TRUE)
377 AND (SPTbit(S,G) == FALSE))
379 AssertTrackingDesired(S,G,I) is true on any interface in which an
380 (S,G) assert might affect our behavior.
382 int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel
*ch
)
384 struct pim_interface
*pim_ifp
;
385 struct interface
*ifp
;
389 zlog_warn("%s: (S,G)=%s: null interface",
390 __PRETTY_FUNCTION__
, ch
->sg_str
);
391 return 0; /* false */
396 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
397 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
);
398 return 0; /* false */
401 /* I in joins(S,G) ? */
402 if (pim_macro_chisin_joins(ch
))
405 /* local_receiver_include(S,G,I) ? */
406 if (local_receiver_include(ch
)) {
408 if (PIM_I_am_DR(pim_ifp
))
411 /* AssertWinner(S,G,I) == me ? */
412 if (ch
->ifassert_winner
.s_addr
== pim_ifp
->primary_address
.s_addr
)
416 /* RPF_interface(S) == I ? */
417 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
) {
418 /* JoinDesired(S,G) ? */
419 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch
->upstream
->flags
))
423 return 0; /* false */