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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "pim_macro.h"
29 #include "pim_iface.h"
30 #include "pim_ifchannel.h"
34 DownstreamJPState(S,G,I) is the per-interface state machine for
35 receiving (S,G) Join/Prune messages.
37 DownstreamJPState(S,G,I) is either Join or Prune-Pending
38 DownstreamJPState(*,G,I) is either Join or Prune-Pending
40 static int downstream_jpstate_isjoined(const struct pim_ifchannel
*ch
)
42 switch (ch
->ifjoin_state
) {
43 case PIM_IFJOIN_NOINFO
:
44 case PIM_IFJOIN_PRUNE
:
45 case PIM_IFJOIN_PRUNE_TMP
:
46 case PIM_IFJOIN_PRUNE_PENDING_TMP
:
49 case PIM_IFJOIN_PRUNE_PENDING
:
56 The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD
57 module or other local membership mechanism has determined that local
58 members on interface I desire to receive traffic sent specifically
61 static int local_receiver_include(const struct pim_ifchannel
*ch
)
63 /* local_receiver_include(S,G,I) ? */
64 return ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
;
68 RFC 4601: 4.1.6. State Summarization Macros
70 The set "joins(S,G)" is the set of all interfaces on which the
71 router has received (S,G) Joins:
74 { all interfaces I such that
75 DownstreamJPState(S,G,I) is either Join or Prune-Pending }
77 DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
79 int pim_macro_chisin_joins(const struct pim_ifchannel
*ch
)
81 return downstream_jpstate_isjoined(ch
);
85 RFC 4601: 4.6.5. Assert State Macros
87 The set "lost_assert(S,G)" is the set of all interfaces on which the
88 router has received (S,G) joins but has lost an (S,G) assert.
91 { all interfaces I such that
92 lost_assert(S,G,I) == true }
94 bool lost_assert(S,G,I) {
95 if ( RPF_interface(S) == I ) {
98 return ( AssertWinner(S,G,I) != NULL AND
99 AssertWinner(S,G,I) != me AND
100 (AssertWinnerMetric(S,G,I) is better
101 than spt_assert_metric(S,I) )
105 AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
106 packet that won an Assert.
108 int pim_macro_ch_lost_assert(const struct pim_ifchannel
*ch
)
110 struct interface
*ifp
;
111 struct pim_interface
*pim_ifp
;
112 struct pim_assert_metric spt_assert_metric
;
116 zlog_warn("%s: (S,G)=%s: null interface", __func__
, ch
->sg_str
);
117 return 0; /* false */
120 /* RPF_interface(S) == I ? */
121 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
)
122 return 0; /* false */
126 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
127 __func__
, ch
->sg_str
, ifp
->name
);
128 return 0; /* false */
131 if (PIM_INADDR_IS_ANY(ch
->ifassert_winner
))
132 return 0; /* false */
134 /* AssertWinner(S,G,I) == me ? */
135 if (ch
->ifassert_winner
.s_addr
== pim_ifp
->primary_address
.s_addr
)
136 return 0; /* false */
138 spt_assert_metric
= pim_macro_spt_assert_metric(
139 &ch
->upstream
->rpf
, pim_ifp
->primary_address
);
141 return pim_assert_metric_better(&ch
->ifassert_winner_metric
,
146 RFC 4601: 4.1.6. State Summarization Macros
149 { all interfaces I such that:
150 ( (I_am_DR( I ) AND lost_assert(S,G,I) == false )
151 OR AssertWinner(S,G,I) == me )
152 AND local_receiver_include(S,G,I) }
154 AssertWinner(S,G,I) is the IP source address of the Assert(S,G)
155 packet that won an Assert.
157 int pim_macro_chisin_pim_include(const struct pim_ifchannel
*ch
)
159 struct pim_interface
*pim_ifp
= ch
->interface
->info
;
160 bool mlag_active
= false;
163 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
164 __func__
, ch
->sg_str
, ch
->interface
->name
);
165 return 0; /* false */
168 /* local_receiver_include(S,G,I) ? */
169 if (!local_receiver_include(ch
))
170 return 0; /* false */
172 /* OR AssertWinner(S,G,I) == me ? */
173 if (ch
->ifassert_winner
.s_addr
== pim_ifp
->primary_address
.s_addr
)
177 * When we have a activeactive interface we need to signal
178 * that this interface is interesting to the upstream
179 * decision to JOIN *if* we are syncing over the interface
181 if (pim_ifp
->activeactive
) {
182 struct pim_upstream
*up
= ch
->upstream
;
184 if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up
->flags
))
190 (PIM_I_am_DR(pim_ifp
) || mlag_active
) &&
191 /* lost_assert(S,G,I) == false ? */
192 (!pim_macro_ch_lost_assert(ch
)));
195 int pim_macro_chisin_joins_or_include(const struct pim_ifchannel
*ch
)
197 if (pim_macro_chisin_joins(ch
))
200 return pim_macro_chisin_pim_include(ch
);
204 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
208 AND (RPF_interface(S) != I)
209 AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
210 (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
212 (+) joins(S,G) (+) pim_include(S,G) ) )
214 CouldAssert(S,G,I) is true for downstream interfaces that would be in
215 the inherited_olist(S,G) if (S,G) assert information was not taken
218 CouldAssert(S,G,I) may be affected by changes in the following:
220 pim_ifp->primary_address
222 ch->ifassert_winner_metric
224 ch->local_ifmembership
226 ch->upstream->rpf.source_nexthop.mrib_metric_preference
227 ch->upstream->rpf.source_nexthop.mrib_route_metric
228 ch->upstream->rpf.source_nexthop.interface
230 int pim_macro_ch_could_assert_eval(const struct pim_ifchannel
*ch
)
232 struct interface
*ifp
;
236 zlog_warn("%s: (S,G)=%s: null interface", __func__
, ch
->sg_str
);
237 return 0; /* false */
240 /* SPTbit(S,G) == true */
241 if (ch
->upstream
->sptbit
== PIM_UPSTREAM_SPTBIT_FALSE
)
242 return 0; /* false */
244 /* RPF_interface(S) != I ? */
245 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
)
246 return 0; /* false */
248 /* I in joins(S,G) (+) pim_include(S,G) ? */
249 return pim_macro_chisin_joins_or_include(ch
);
253 RFC 4601: 4.6.3. Assert Metrics
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:
259 spt_assert_metric(S,I) {
260 return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)}
263 struct pim_assert_metric
pim_macro_spt_assert_metric(const struct pim_rpf
*rpf
,
264 struct in_addr ifaddr
)
266 struct pim_assert_metric metric
;
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
;
277 RFC 4601: 4.6.3. Assert Metrics
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:
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)
289 return infinite_assert_metric()
293 struct pim_assert_metric
294 pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel
*ch
)
296 struct pim_interface
*pim_ifp
;
298 pim_ifp
= ch
->interface
->info
;
301 if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
302 return pim_macro_spt_assert_metric(
303 &ch
->upstream
->rpf
, pim_ifp
->primary_address
);
307 return router
->infinite_assert_metric
;
311 RFC 4601 4.2. Data Packet Forwarding Rules
314 inherited_olist(S,G) =
315 inherited_olist(S,G,rpt) (+)
316 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
318 static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel
*ch
)
320 if (pim_macro_ch_lost_assert(ch
))
321 return 0; /* false */
323 return pim_macro_chisin_joins_or_include(ch
);
327 RFC 4601 4.2. Data Packet Forwarding Rules
328 RFC 4601 4.8.2. PIM-SSM-Only Routers
330 Additionally, the Packet forwarding rules of Section 4.2 can be
331 simplified in a PIM-SSM-only router:
333 iif is the incoming interface of the packet.
335 if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
336 oiflist = inherited_olist(S,G)
337 } else if (iif is in inherited_olist(S,G)) {
338 send Assert(S,G) on iif
340 oiflist = oiflist (-) iif
341 forward packet on all interfaces in oiflist
344 inherited_olist(S,G) =
345 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
348 - The following test is performed as response to WRONGVIF kernel
350 if (iif is in inherited_olist(S,G)) {
351 send Assert(S,G) on iif
353 See pim_mroute.c mroute_msg().
355 int pim_macro_chisin_oiflist(const struct pim_ifchannel
*ch
)
357 if (ch
->upstream
->join_state
== PIM_UPSTREAM_NOTJOINED
) {
358 /* oiflist is NULL */
359 return 0; /* false */
362 /* oiflist = oiflist (-) iif */
363 if (ch
->interface
== ch
->upstream
->rpf
.source_nexthop
.interface
)
364 return 0; /* false */
366 return pim_macro_chisin_inherited_olist(ch
);
370 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
372 AssertTrackingDesired(S,G,I) =
373 (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
374 (+) ( pim_include(*,G) (-) pim_exclude(S,G) )
377 OR (local_receiver_include(S,G,I) == true
378 AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me)))
379 OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == true))
380 OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == true)
381 AND (SPTbit(S,G) == false))
383 AssertTrackingDesired(S,G,I) is true on any interface in which an
384 (S,G) assert might affect our behavior.
386 int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel
*ch
)
388 struct pim_interface
*pim_ifp
;
389 struct interface
*ifp
;
393 zlog_warn("%s: (S,G)=%s: null interface", __func__
, ch
->sg_str
);
394 return 0; /* false */
399 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
400 __func__
, ch
->sg_str
, ch
->interface
->name
);
401 return 0; /* false */
404 /* I in joins(S,G) ? */
405 if (pim_macro_chisin_joins(ch
))
408 /* local_receiver_include(S,G,I) ? */
409 if (local_receiver_include(ch
)) {
411 if (PIM_I_am_DR(pim_ifp
))
414 /* AssertWinner(S,G,I) == me ? */
415 if (ch
->ifassert_winner
.s_addr
416 == pim_ifp
->primary_address
.s_addr
)
420 /* RPF_interface(S) == I ? */
421 if (ch
->upstream
->rpf
.source_nexthop
.interface
== ifp
) {
422 /* JoinDesired(S,G) ? */
423 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch
->upstream
->flags
))
427 return 0; /* false */