]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_ifchannel.c
pimd: Remove unneeded parameter
[mirror_frr.git] / pimd / pim_ifchannel.c
CommitLineData
12e41d03
DL
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
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "thread.h"
25#include "memory.h"
744d91b3 26#include "if.h"
c8507a16 27#include "vrf.h"
12e41d03
DL
28
29#include "pimd.h"
30#include "pim_str.h"
31#include "pim_iface.h"
32#include "pim_ifchannel.h"
33#include "pim_zebra.h"
34#include "pim_time.h"
35#include "pim_msg.h"
36#include "pim_pim.h"
37#include "pim_join.h"
38#include "pim_rpf.h"
39#include "pim_macro.h"
dfbbce1d 40#include "pim_oil.h"
4a40c37a 41#include "pim_upstream.h"
12e41d03 42
3fdfd943
DS
43int
44pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
45{
46 struct pim_interface *pim_ifp1;
47 struct pim_interface *pim_ifp2;
48
49 if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
50 return -1;
51
52 if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
53 return 1;
54
55 if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
56 return -1;
57
58 if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
59 return 1;
60
61 pim_ifp1 = ch1->interface->info;
62 pim_ifp2 = ch2->interface->info;
63 if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr))
64 return -1;
65
66 if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr))
67 return 1;
68
69 if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
70 return -1;
71
72 if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
73 return 1;
74
75 return 0;
76}
77
1a10fc74
DS
78/*
79 * A (*,G) or a (*,*) is going away
80 * remove the parent pointer from
81 * those pointing at us
82 */
83static void
84pim_ifchannel_remove_children (struct pim_ifchannel *ch)
85{
1a10fc74
DS
86 struct pim_ifchannel *child;
87
3fdfd943 88 if (!ch->sources)
1a10fc74
DS
89 return;
90
3fdfd943 91 while (!list_isempty (ch->sources))
1a10fc74 92 {
3fdfd943
DS
93 child = listnode_head (ch->sources);
94 child->parent = NULL;
95 listnode_delete (ch->sources, child);
1a10fc74
DS
96 }
97}
98
99/*
100 * A (*,G) or a (*,*) is being created
101 * find all the children that would point
102 * at us.
103 */
104static void
105pim_ifchannel_find_new_children (struct pim_ifchannel *ch)
106{
107 struct pim_interface *pim_ifp = ch->interface->info;
108 struct pim_ifchannel *child;
109 struct listnode *ch_node;
110
111 // Basic Sanity that we are not being silly
4ed0af70
DS
112 if ((ch->sg.src.s_addr != INADDR_ANY) &&
113 (ch->sg.grp.s_addr != INADDR_ANY))
1a10fc74
DS
114 return;
115
4ed0af70
DS
116 if ((ch->sg.src.s_addr == INADDR_ANY) &&
117 (ch->sg.grp.s_addr == INADDR_ANY))
1a10fc74
DS
118 return;
119
120 for (ALL_LIST_ELEMENTS_RO (pim_ifp->pim_ifchannel_list, ch_node, child))
121 {
4ed0af70
DS
122 if ((ch->sg.grp.s_addr != INADDR_ANY) &&
123 (child->sg.grp.s_addr == ch->sg.grp.s_addr) &&
1a10fc74 124 (child != ch))
3fdfd943
DS
125 {
126 child->parent = ch;
127 listnode_add_sort (ch->sources, child);
128 }
1a10fc74
DS
129 }
130}
131
12e41d03
DL
132void pim_ifchannel_free(struct pim_ifchannel *ch)
133{
12e41d03
DL
134 XFREE(MTYPE_PIM_IFCHANNEL, ch);
135}
136
137void pim_ifchannel_delete(struct pim_ifchannel *ch)
138{
139 struct pim_interface *pim_ifp;
140
141 pim_ifp = ch->interface->info;
12e41d03 142
ef71d1f8
DS
143 if (ch->upstream->channel_oil)
144 {
f663aa7a
DS
145 uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
146 if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
147 mask = PIM_OIF_FLAG_PROTO_IGMP;
148
149 pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, mask);
ef71d1f8
DS
150 /*
151 * Do we have any S,G's that are inheriting?
152 * Nuke from on high too.
153 */
154 if (ch->upstream->sources)
155 {
156 struct pim_upstream *child;
157 struct listnode *up_node;
158
159 for (ALL_LIST_ELEMENTS_RO (ch->upstream->sources, up_node, child))
781a1745 160 pim_channel_del_oif (child->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
ef71d1f8
DS
161 }
162 }
163
1a10fc74
DS
164 /*
165 * When this channel is removed
166 * we need to find all our children
167 * and make sure our pointers are fixed
168 */
169 pim_ifchannel_remove_children (ch);
170
3fdfd943
DS
171 if (ch->sources)
172 list_delete (ch->sources);
173
12e41d03
DL
174 if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
175 pim_upstream_update_join_desired(ch->upstream);
176 }
177
e5905a3b 178 pim_upstream_del(ch->upstream, __PRETTY_FUNCTION__);
5ce79466 179 ch->upstream = NULL;
12e41d03
DL
180
181 THREAD_OFF(ch->t_ifjoin_expiry_timer);
182 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
183 THREAD_OFF(ch->t_ifassert_timer);
184
3fdfd943
DS
185 if (ch->parent)
186 {
187 listnode_delete (ch->parent->sources, ch);
188 ch->parent = NULL;
189 }
12e41d03
DL
190 /*
191 notice that listnode_delete() can't be moved
192 into pim_ifchannel_free() because the later is
193 called by list_delete_all_node()
194 */
195 listnode_delete(pim_ifp->pim_ifchannel_list, ch);
ea4a71fc 196 listnode_delete(pim_ifchannel_list, ch);
12e41d03
DL
197
198 pim_ifchannel_free(ch);
199}
cb24fec4
DS
200
201void
202pim_ifchannel_delete_all (struct interface *ifp)
203{
204 struct pim_interface *pim_ifp;
205 struct listnode *ifchannel_node;
206 struct listnode *ifchannel_nextnode;
207 struct pim_ifchannel *ifchannel;
208
209 pim_ifp = ifp->info;
ef71d1f8
DS
210 if (!pim_ifp)
211 return;
cb24fec4
DS
212
213 for (ALL_LIST_ELEMENTS (pim_ifp->pim_ifchannel_list, ifchannel_node,
214 ifchannel_nextnode, ifchannel))
215 {
216 pim_ifchannel_delete (ifchannel);
217 }
218}
12e41d03
DL
219
220static void delete_on_noinfo(struct pim_ifchannel *ch)
221{
1be8f9d3 222 if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO &&
45b0c8f3
DS
223 ch->ifjoin_state == PIM_IFJOIN_NOINFO &&
224 ch->t_ifjoin_expiry_timer == NULL)
12e41d03 225 pim_ifchannel_delete(ch);
1be8f9d3 226
12e41d03
DL
227}
228
229void pim_ifchannel_ifjoin_switch(const char *caller,
230 struct pim_ifchannel *ch,
231 enum pim_ifjoin_state new_state)
232{
233 enum pim_ifjoin_state old_state = ch->ifjoin_state;
234
04329d4e 235 if (PIM_DEBUG_PIM_EVENTS)
594a78cc
DS
236 zlog_debug ("PIM_IFCHANNEL(%s): %s is switching from %s to %s",
237 ch->interface->name,
8bfb8b67 238 ch->sg_str,
04329d4e
DS
239 pim_ifchannel_ifjoin_name (ch->ifjoin_state),
240 pim_ifchannel_ifjoin_name (new_state));
241
242
12e41d03 243 if (old_state == new_state) {
7adf0260
DS
244 if (PIM_DEBUG_PIM_EVENTS) {
245 zlog_debug("%s calledby %s: non-transition on state %d (%s)",
246 __PRETTY_FUNCTION__, caller, new_state,
247 pim_ifchannel_ifjoin_name(new_state));
248 }
12e41d03
DL
249 return;
250 }
251
12e41d03
DL
252 ch->ifjoin_state = new_state;
253
6578dfa3
DS
254 if (ch->sg.src.s_addr == INADDR_ANY)
255 {
256 struct pim_upstream *up = ch->upstream;
257 struct pim_upstream *child;
258 struct listnode *up_node;
259
260 if (up)
261 {
262 if (ch->ifjoin_state == PIM_IFJOIN_NOINFO)
263 {
264 for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
265 {
266 struct channel_oil *c_oil = child->channel_oil;
267 struct pim_interface *pim_ifp = ch->interface->info;
268
269 if (PIM_DEBUG_PIM_TRACE)
270 zlog_debug("%s %s: Prune(S,G)=%s from %s",
271 __FILE__, __PRETTY_FUNCTION__,
272 child->sg_str, up->sg_str);
273 if (!c_oil)
274 continue;
275
276 if (!pim_upstream_evaluate_join_desired (child))
a118e71d
DS
277 {
278 pim_channel_del_oif (c_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
279 pim_upstream_update_join_desired (child);
280 }
6578dfa3
DS
281
282 /*
283 * If the S,G has no if channel and the c_oil still
284 * has output here then the *,G was supplying the implied
285 * if channel. So remove it.
a118e71d 286 * I think this is dead code now. is it?
6578dfa3
DS
287 */
288 if (!ch && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
781a1745 289 pim_channel_del_oif (c_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
6578dfa3
DS
290 }
291 }
292 if (ch->ifjoin_state == PIM_IFJOIN_JOIN)
293 {
294 for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
295 {
296 if (PIM_DEBUG_PIM_TRACE)
297 zlog_debug("%s %s: Join(S,G)=%s from %s",
298 __FILE__, __PRETTY_FUNCTION__,
299 child->sg_str, up->sg_str);
300
301 if (pim_upstream_evaluate_join_desired (child))
302 {
781a1745 303 pim_channel_add_oif (child->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
a118e71d 304 pim_upstream_update_join_desired (child);
6578dfa3
DS
305 }
306 }
307 }
308 }
309 }
12e41d03 310 /* Transition to/from NOINFO ? */
1be8f9d3
DS
311 if ((old_state == PIM_IFJOIN_NOINFO) ||
312 (new_state == PIM_IFJOIN_NOINFO)) {
12e41d03
DL
313
314 if (PIM_DEBUG_PIM_EVENTS) {
ee1a477a 315 zlog_debug("PIM_IFCHANNEL_%s: (S,G)=%s on interface %s",
12e41d03 316 ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
8bfb8b67 317 ch->sg_str, ch->interface->name);
12e41d03
DL
318 }
319
320 /*
321 Record uptime of state transition to/from NOINFO
322 */
323 ch->ifjoin_creation = pim_time_monotonic_sec();
324
325 pim_upstream_update_join_desired(ch->upstream);
326 pim_ifchannel_update_could_assert(ch);
327 pim_ifchannel_update_assert_tracking_desired(ch);
328 }
329}
330
331const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
332{
333 switch (ifjoin_state) {
be4791f2
DS
334 case PIM_IFJOIN_NOINFO: return "NOINFO";
335 case PIM_IFJOIN_JOIN: return "JOIN";
336 case PIM_IFJOIN_PRUNE: return "PRUNE";
337 case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
338 case PIM_IFJOIN_PRUNE_TMP: return "PRUNET";
339 case PIM_IFJOIN_PRUNE_PENDING_TMP: return "PRUNEPT";
12e41d03
DL
340 }
341
342 return "ifjoin_bad_state";
343}
344
345const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state)
346{
347 switch (ifassert_state) {
348 case PIM_IFASSERT_NOINFO: return "NOINFO";
349 case PIM_IFASSERT_I_AM_WINNER: return "WINNER";
350 case PIM_IFASSERT_I_AM_LOSER: return "LOSER";
351 }
352
353 return "ifassert_bad_state";
354}
355
356/*
357 RFC 4601: 4.6.5. Assert State Macros
358
359 AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I)
360 defaults to Infinity when in the NoInfo state.
361*/
362void reset_ifassert_state(struct pim_ifchannel *ch)
363{
364 THREAD_OFF(ch->t_ifassert_timer);
365
366 pim_ifassert_winner_set(ch,
367 PIM_IFASSERT_NOINFO,
368 qpim_inaddr_any,
369 qpim_infinite_assert_metric);
370}
371
12e41d03 372struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
4ed0af70 373 struct prefix_sg *sg)
12e41d03
DL
374{
375 struct pim_interface *pim_ifp;
376 struct listnode *ch_node;
377 struct pim_ifchannel *ch;
378
379 zassert(ifp);
380
381 pim_ifp = ifp->info;
382
383 if (!pim_ifp) {
5074a423 384 zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
12e41d03 385 __PRETTY_FUNCTION__,
5074a423 386 pim_str_sg_dump (sg),
12e41d03
DL
387 ifp->name);
388 return 0;
389 }
390
391 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
392 if (
4ed0af70
DS
393 (sg->src.s_addr == ch->sg.src.s_addr) &&
394 (sg->grp.s_addr == ch->sg.grp.s_addr)
12e41d03
DL
395 ) {
396 return ch;
397 }
398 }
399
400 return 0;
401}
402
403static void ifmembership_set(struct pim_ifchannel *ch,
404 enum pim_ifmembership membership)
405{
406 if (ch->local_ifmembership == membership)
407 return;
408
7adf0260 409 if (PIM_DEBUG_PIM_EVENTS) {
ee1a477a 410 zlog_debug("%s: (S,G)=%s membership now is %s on interface %s",
12e41d03 411 __PRETTY_FUNCTION__,
8bfb8b67 412 ch->sg_str,
12e41d03
DL
413 membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
414 ch->interface->name);
415 }
416
417 ch->local_ifmembership = membership;
418
419 pim_upstream_update_join_desired(ch->upstream);
420 pim_ifchannel_update_could_assert(ch);
421 pim_ifchannel_update_assert_tracking_desired(ch);
422}
423
424
425void pim_ifchannel_membership_clear(struct interface *ifp)
426{
427 struct pim_interface *pim_ifp;
428 struct listnode *ch_node;
429 struct pim_ifchannel *ch;
430
431 pim_ifp = ifp->info;
432 zassert(pim_ifp);
433
434 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
435 ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
436 }
437}
438
439void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
440{
441 struct pim_interface *pim_ifp;
442 struct listnode *node;
443 struct listnode *next_node;
444 struct pim_ifchannel *ch;
445
446 pim_ifp = ifp->info;
447 zassert(pim_ifp);
448
449 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
450 delete_on_noinfo(ch);
451 }
452}
453
1a10fc74
DS
454/*
455 * For a given Interface, if we are given a S,G
456 * Find the *,G (If we have it).
457 * If we are passed a *,G, find the *,* ifchannel
458 * if we have it.
459 */
460static struct pim_ifchannel *
3fdfd943 461pim_ifchannel_find_parent (struct pim_ifchannel *ch)
1a10fc74 462{
3fdfd943
DS
463 struct prefix_sg parent_sg = ch->sg;
464 struct pim_ifchannel *parent = NULL;
1a10fc74
DS
465
466 // (S,G)
3fdfd943
DS
467 if ((parent_sg.src.s_addr != INADDR_ANY) &&
468 (parent_sg.grp.s_addr != INADDR_ANY))
1a10fc74 469 {
4ed0af70 470 parent_sg.src.s_addr = INADDR_ANY;
3fdfd943
DS
471 parent = pim_ifchannel_find (ch->interface, &parent_sg);
472
473 if (parent)
474 listnode_add (parent->sources, ch);
475 return parent;
1a10fc74
DS
476 }
477
3fdfd943 478 return NULL;
1a10fc74
DS
479}
480
481struct pim_ifchannel *
482pim_ifchannel_add(struct interface *ifp,
4a40c37a 483 struct prefix_sg *sg, int flags)
12e41d03 484{
535db05b 485 struct pim_interface *pim_ifp;
12e41d03 486 struct pim_ifchannel *ch;
535db05b 487 struct pim_upstream *up;
12e41d03 488
5074a423 489 ch = pim_ifchannel_find(ifp, sg);
12e41d03
DL
490 if (ch)
491 return ch;
492
535db05b 493 pim_ifp = ifp->info;
535db05b 494
e5905a3b 495 up = pim_upstream_add(sg, NULL, flags, __PRETTY_FUNCTION__);
535db05b 496 if (!up) {
5074a423 497 zlog_err("%s: could not attach upstream (S,G)=%s on interface %s",
535db05b 498 __PRETTY_FUNCTION__,
5074a423 499 pim_str_sg_dump (sg), ifp->name);
535db05b
DS
500 return NULL;
501 }
502
98573e19 503 ch = XCALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
535db05b 504 if (!ch) {
5074a423 505 zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s",
535db05b 506 __PRETTY_FUNCTION__,
8bfb8b67 507 up->sg_str, ifp->name);
3fdfd943
DS
508
509 pim_upstream_del (up, __PRETTY_FUNCTION__);
535db05b
DS
510 return NULL;
511 }
12e41d03 512
535db05b
DS
513 ch->flags = 0;
514 ch->upstream = up;
515 ch->interface = ifp;
5074a423 516 ch->sg = *sg;
8bfb8b67 517 pim_str_sg_set (sg, ch->sg_str);
3fdfd943
DS
518 ch->parent = pim_ifchannel_find_parent (ch);
519 if (ch->sg.src.s_addr == INADDR_ANY)
520 {
521 ch->sources = list_new ();
522 ch->sources->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
523 }
524 else
525 ch->sources = NULL;
526
1a10fc74 527 pim_ifchannel_find_new_children (ch);
535db05b
DS
528 ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
529
530 ch->ifjoin_state = PIM_IFJOIN_NOINFO;
531 ch->t_ifjoin_expiry_timer = NULL;
532 ch->t_ifjoin_prune_pending_timer = NULL;
533 ch->ifjoin_creation = 0;
534
535 ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
536 ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch);
537
538 ch->ifassert_winner.s_addr = 0;
539
540 /* Assert state */
541 ch->t_ifassert_timer = NULL;
98573e19 542 ch->ifassert_state = PIM_IFASSERT_NOINFO;
535db05b
DS
543 reset_ifassert_state(ch);
544 if (pim_macro_ch_could_assert_eval(ch))
545 PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
546 else
547 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
548
549 if (pim_macro_assert_tracking_desired_eval(ch))
550 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
551 else
552 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
553
554 /* Attach to list */
bbd64ce1 555 listnode_add_sort(pim_ifp->pim_ifchannel_list, ch);
ea4a71fc 556 listnode_add_sort(pim_ifchannel_list, ch);
535db05b 557
535db05b 558 return ch;
12e41d03
DL
559}
560
561static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
562{
563 pim_forward_stop(ch);
564 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
565 delete_on_noinfo(ch);
566}
567
568static int on_ifjoin_expiry_timer(struct thread *t)
569{
570 struct pim_ifchannel *ch;
571
12e41d03 572 ch = THREAD_ARG(t);
12e41d03 573
59ba0ac3 574 ch->t_ifjoin_expiry_timer = NULL;
12e41d03 575
12e41d03
DL
576 ifjoin_to_noinfo(ch);
577 /* ch may have been deleted */
578
579 return 0;
580}
581
12e41d03
DL
582static int on_ifjoin_prune_pending_timer(struct thread *t)
583{
584 struct pim_ifchannel *ch;
585 int send_prune_echo; /* boolean */
586 struct interface *ifp;
587 struct pim_interface *pim_ifp;
12e41d03 588
12e41d03 589 ch = THREAD_ARG(t);
12e41d03 590
59ba0ac3 591 ch->t_ifjoin_prune_pending_timer = NULL;
12e41d03 592
1e3a5132
DS
593 if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING)
594 {
595 /* Send PruneEcho(S,G) ? */
596 ifp = ch->interface;
597 pim_ifp = ifp->info;
598 send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
12e41d03 599
1e3a5132
DS
600 ifjoin_to_noinfo(ch);
601 /* from here ch may have been deleted */
12e41d03 602
1e3a5132
DS
603 if (send_prune_echo)
604 pim_joinprune_send (ifp, pim_ifp->primary_address,
605 ch->upstream, 0);
606 }
607 else
608 {
609 zlog_warn("%s: IFCHANNEL%s Prune Pending Timer Popped while in %s state",
610 __PRETTY_FUNCTION__, pim_str_sg_dump (&ch->sg),
611 pim_ifchannel_ifjoin_name (ch->ifjoin_state));
612 }
12e41d03
DL
613
614 return 0;
615}
616
617static void check_recv_upstream(int is_join,
618 struct interface *recv_ifp,
619 struct in_addr upstream,
4ed0af70 620 struct prefix_sg *sg,
12e41d03
DL
621 uint8_t source_flags,
622 int holdtime)
623{
624 struct pim_upstream *up;
625
626 /* Upstream (S,G) in Joined state ? */
01d45d04 627 up = pim_upstream_find(sg);
12e41d03
DL
628 if (!up)
629 return;
630 if (up->join_state != PIM_UPSTREAM_JOINED)
631 return;
632
633 /* Upstream (S,G) in Joined state */
634
63c59d0c 635 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
12e41d03 636 /* RPF'(S,G) not found */
01d45d04 637 zlog_warn("%s %s: RPF'%s not found",
12e41d03 638 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 639 up->sg_str);
12e41d03
DL
640 return;
641 }
642
643 /* upstream directed to RPF'(S,G) ? */
63c59d0c 644 if (upstream.s_addr != up->rpf.rpf_addr.u.prefix4.s_addr) {
eaa54bdb
DW
645 char up_str[INET_ADDRSTRLEN];
646 char rpf_str[PREFIX_STRLEN];
12e41d03 647 pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
63c59d0c 648 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
01d45d04 649 zlog_warn("%s %s: (S,G)=%s upstream=%s not directed to RPF'(S,G)=%s on interface %s",
12e41d03 650 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 651 up->sg_str,
12e41d03
DL
652 up_str, rpf_str, recv_ifp->name);
653 return;
654 }
655 /* upstream directed to RPF'(S,G) */
656
657 if (is_join) {
658 /* Join(S,G) to RPF'(S,G) */
63c59d0c 659 pim_upstream_join_suppress(up, up->rpf.rpf_addr.u.prefix4, holdtime);
12e41d03
DL
660 return;
661 }
662
663 /* Prune to RPF'(S,G) */
664
665 if (source_flags & PIM_RPT_BIT_MASK) {
666 if (source_flags & PIM_WILDCARD_BIT_MASK) {
667 /* Prune(*,G) to RPF'(S,G) */
c48a612c 668 pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", up);
12e41d03
DL
669 return;
670 }
671
672 /* Prune(S,G,rpt) to RPF'(S,G) */
c48a612c 673 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", up);
12e41d03
DL
674 return;
675 }
676
677 /* Prune(S,G) to RPF'(S,G) */
c48a612c 678 pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up);
12e41d03
DL
679}
680
681static int nonlocal_upstream(int is_join,
682 struct interface *recv_ifp,
683 struct in_addr upstream,
4ed0af70 684 struct prefix_sg *sg,
12e41d03
DL
685 uint8_t source_flags,
686 uint16_t holdtime)
687{
688 struct pim_interface *recv_pim_ifp;
689 int is_local; /* boolean */
690
691 recv_pim_ifp = recv_ifp->info;
692 zassert(recv_pim_ifp);
693
694 is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
695
a770ef90 696 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
eaa54bdb 697 char up_str[INET_ADDRSTRLEN];
12e41d03 698 pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
01d45d04 699 zlog_warn("%s: recv %s (S,G)=%s to %s upstream=%s on %s",
12e41d03
DL
700 __PRETTY_FUNCTION__,
701 is_join ? "join" : "prune",
01d45d04 702 pim_str_sg_dump (sg),
12e41d03
DL
703 is_local ? "local" : "non-local",
704 up_str, recv_ifp->name);
705 }
706
707 if (is_local)
708 return 0;
709
710 /*
711 Since recv upstream addr was not directed to our primary
712 address, check if we should react to it in any way.
713 */
01d45d04 714 check_recv_upstream(is_join, recv_ifp, upstream, sg,
12e41d03
DL
715 source_flags, holdtime);
716
717 return 1; /* non-local */
718}
719
720void pim_ifchannel_join_add(struct interface *ifp,
721 struct in_addr neigh_addr,
722 struct in_addr upstream,
4ed0af70 723 struct prefix_sg *sg,
12e41d03
DL
724 uint8_t source_flags,
725 uint16_t holdtime)
726{
727 struct pim_interface *pim_ifp;
728 struct pim_ifchannel *ch;
729
730 if (nonlocal_upstream(1 /* join */, ifp, upstream,
01d45d04 731 sg, source_flags, holdtime)) {
12e41d03
DL
732 return;
733 }
734
4a40c37a 735 ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
12e41d03
DL
736 if (!ch)
737 return;
738
739 /*
740 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
741
742 Transitions from "I am Assert Loser" State
743
744 Receive Join(S,G) on Interface I
745
746 We receive a Join(S,G) that has the Upstream Neighbor Address
747 field set to my primary IP address on interface I. The action is
748 to transition to NoInfo state, delete this (S,G) assert state
749 (Actions A5 below), and allow the normal PIM Join/Prune mechanisms
750 to operate.
751
752 Notice: The nonlocal_upstream() test above ensures the upstream
753 address of the join message is our primary address.
754 */
755 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
eaa54bdb 756 char neigh_str[INET_ADDRSTRLEN];
12e41d03 757 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
5074a423 758 zlog_warn("%s: Assert Loser recv Join%s from %s on %s",
12e41d03 759 __PRETTY_FUNCTION__,
8bfb8b67 760 ch->sg_str, neigh_str, ifp->name);
12e41d03
DL
761
762 assert_action_a5(ch);
763 }
764
765 pim_ifp = ifp->info;
766 zassert(pim_ifp);
767
768 switch (ch->ifjoin_state) {
769 case PIM_IFJOIN_NOINFO:
770 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
771 if (pim_macro_chisin_oiflist(ch)) {
5b668dd7 772 pim_upstream_inherited_olist (ch->upstream);
12e41d03
DL
773 pim_forward_start(ch);
774 }
775 break;
776 case PIM_IFJOIN_JOIN:
777 zassert(!ch->t_ifjoin_prune_pending_timer);
778
779 /*
780 In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a
781 previously received join message with holdtime=0xFFFF.
782 */
783 if (ch->t_ifjoin_expiry_timer) {
784 unsigned long remain =
785 thread_timer_remain_second(ch->t_ifjoin_expiry_timer);
786 if (remain > holdtime) {
787 /*
788 RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages
789
790 Transitions from Join State
791
792 The (S,G) downstream state machine on interface I remains in
793 Join state, and the Expiry Timer (ET) is restarted, set to
794 maximum of its current value and the HoldTime from the
795 triggering Join/Prune message.
796
797 Conclusion: Do not change the ET if the current value is
798 higher than the received join holdtime.
799 */
800 return;
801 }
802 }
803 THREAD_OFF(ch->t_ifjoin_expiry_timer);
804 break;
be4791f2 805 case PIM_IFJOIN_PRUNE:
220d8a49
DS
806 if (source_flags & PIM_ENCODE_RPT_BIT)
807 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
be4791f2 808 break;
12e41d03 809 case PIM_IFJOIN_PRUNE_PENDING:
1e3a5132 810 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
220d8a49 811 if (source_flags & PIM_ENCODE_RPT_BIT)
220d8a49 812 {
1e3a5132
DS
813 THREAD_OFF(ch->t_ifjoin_expiry_timer);
814 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
220d8a49 815 }
1e3a5132
DS
816 else
817 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
12e41d03 818 break;
be4791f2 819 case PIM_IFJOIN_PRUNE_TMP:
be4791f2
DS
820 break;
821 case PIM_IFJOIN_PRUNE_PENDING_TMP:
be4791f2 822 break;
12e41d03
DL
823 }
824
12e41d03
DL
825 if (holdtime != 0xFFFF) {
826 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
827 on_ifjoin_expiry_timer,
828 ch, holdtime);
829 }
830}
831
832void pim_ifchannel_prune(struct interface *ifp,
833 struct in_addr upstream,
4ed0af70 834 struct prefix_sg *sg,
12e41d03
DL
835 uint8_t source_flags,
836 uint16_t holdtime)
837{
838 struct pim_ifchannel *ch;
1405c852 839 struct pim_interface *pim_ifp;
12e41d03
DL
840 int jp_override_interval_msec;
841
842 if (nonlocal_upstream(0 /* prune */, ifp, upstream,
01d45d04 843 sg, source_flags, holdtime)) {
12e41d03
DL
844 return;
845 }
846
df90067a
DS
847 ch = pim_ifchannel_find (ifp, sg);
848 if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT))
849 {
850 if (PIM_DEBUG_TRACE)
851 zlog_debug ("%s: Received prune with no relevant ifchannel %s(%s) state: %d",
852 __PRETTY_FUNCTION__, ifp->name, pim_str_sg_dump (sg), source_flags);
853 return;
854 }
855
4a40c37a 856 ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
12e41d03
DL
857 if (!ch)
858 return;
859
1405c852
DS
860 pim_ifp = ifp->info;
861
12e41d03
DL
862 switch (ch->ifjoin_state) {
863 case PIM_IFJOIN_NOINFO:
1405c852
DS
864 if (source_flags & PIM_ENCODE_RPT_BIT)
865 {
866 PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
867 ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
868 if (listcount(pim_ifp->pim_neighbor_list) > 1)
869 jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
870 else
871 jp_override_interval_msec = 0; /* schedule to expire immediately */
872 /* If we called ifjoin_prune() directly instead, care should
873 be taken not to use "ch" afterwards since it would be
874 deleted. */
875
876 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
877 THREAD_OFF(ch->t_ifjoin_expiry_timer);
878 THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
879 on_ifjoin_prune_pending_timer,
880 ch, jp_override_interval_msec);
881 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
882 on_ifjoin_expiry_timer,
883 ch, holdtime);
884 }
885 break;
12e41d03
DL
886 case PIM_IFJOIN_PRUNE_PENDING:
887 /* nothing to do */
888 break;
889 case PIM_IFJOIN_JOIN:
1405c852 890 THREAD_OFF(ch->t_ifjoin_expiry_timer);
12e41d03 891
1405c852 892 pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
12e41d03 893
1405c852
DS
894 if (listcount(pim_ifp->pim_neighbor_list) > 1)
895 jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
896 else
897 jp_override_interval_msec = 0; /* schedule to expire immediately */
898 /* If we called ifjoin_prune() directly instead, care should
899 be taken not to use "ch" afterwards since it would be
900 deleted. */
901 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
902 THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
903 on_ifjoin_prune_pending_timer,
904 ch, jp_override_interval_msec);
12e41d03 905 break;
be4791f2 906 case PIM_IFJOIN_PRUNE:
1405c852
DS
907 if (source_flags & PIM_ENCODE_RPT_BIT)
908 {
909 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
910 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
911 on_ifjoin_expiry_timer,
912 ch, holdtime);
913 }
914 break;
be4791f2 915 case PIM_IFJOIN_PRUNE_TMP:
1405c852
DS
916 if (source_flags & PIM_ENCODE_RPT_BIT)
917 {
918 ch->ifjoin_state = PIM_IFJOIN_PRUNE;
919 THREAD_OFF(ch->t_ifjoin_expiry_timer);
920 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
921 on_ifjoin_expiry_timer,
922 ch, holdtime);
923 }
924 break;
be4791f2 925 case PIM_IFJOIN_PRUNE_PENDING_TMP:
1405c852
DS
926 if (source_flags & PIM_ENCODE_RPT_BIT)
927 {
928 ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
929 THREAD_OFF(ch->t_ifjoin_expiry_timer);
930 THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
931 on_ifjoin_expiry_timer,
932 ch, holdtime);
933 }
be4791f2 934 break;
12e41d03 935 }
12e41d03
DL
936}
937
f663aa7a
DS
938int
939pim_ifchannel_local_membership_add(struct interface *ifp,
940 struct prefix_sg *sg)
12e41d03
DL
941{
942 struct pim_ifchannel *ch;
943 struct pim_interface *pim_ifp;
944
945 /* PIM enabled on interface? */
946 pim_ifp = ifp->info;
947 if (!pim_ifp)
f663aa7a 948 return 0;
12e41d03 949 if (!PIM_IF_TEST_PIM(pim_ifp->options))
f663aa7a 950 return 0;
12e41d03 951
4a40c37a 952 ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
12e41d03 953 if (!ch) {
f663aa7a 954 return 0;
12e41d03
DL
955 }
956
957 ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
958
dfbbce1d
DS
959 if (sg->src.s_addr == INADDR_ANY)
960 {
961 struct pim_upstream *up = pim_upstream_find (sg);
962 struct pim_upstream *child;
963 struct listnode *up_node;
964
03417ccd 965 for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
dfbbce1d 966 {
03417ccd 967 if (PIM_DEBUG_EVENTS)
8bfb8b67
DS
968 zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
969 __FILE__, __PRETTY_FUNCTION__,
970 child->sg_str, ifp->name, up->sg_str);
03417ccd
DS
971
972 if (pim_upstream_evaluate_join_desired (child))
973 {
781a1745 974 pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
03417ccd
DS
975 pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
976 }
dfbbce1d
DS
977 }
978 }
f663aa7a
DS
979
980 return 1;
12e41d03
DL
981}
982
983void pim_ifchannel_local_membership_del(struct interface *ifp,
4ed0af70 984 struct prefix_sg *sg)
12e41d03
DL
985{
986 struct pim_ifchannel *ch;
987 struct pim_interface *pim_ifp;
988
989 /* PIM enabled on interface? */
990 pim_ifp = ifp->info;
991 if (!pim_ifp)
992 return;
993 if (!PIM_IF_TEST_PIM(pim_ifp->options))
994 return;
995
1103466b 996 ch = pim_ifchannel_find(ifp, sg);
12e41d03
DL
997 if (!ch)
998 return;
999
1000 ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
1001
dfbbce1d
DS
1002 if (sg->src.s_addr == INADDR_ANY)
1003 {
1004 struct pim_upstream *up = pim_upstream_find (sg);
1005 struct pim_upstream *child;
1006 struct listnode *up_node;
1007
03417ccd 1008 for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
dfbbce1d 1009 {
03417ccd
DS
1010 struct channel_oil *c_oil = child->channel_oil;
1011 struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg);
1012 struct pim_interface *pim_ifp = ifp->info;
1013
1014 if (PIM_DEBUG_EVENTS)
8bfb8b67
DS
1015 zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
1016 __FILE__, __PRETTY_FUNCTION__,
1017 up->sg_str, ifp->name, child->sg_str);
03417ccd 1018
b72f79a9 1019 if (c_oil && !pim_upstream_evaluate_join_desired (child))
781a1745 1020 pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
03417ccd
DS
1021
1022 /*
1023 * If the S,G has no if channel and the c_oil still
1024 * has output here then the *,G was supplying the implied
1025 * if channel. So remove it.
1026 */
b72f79a9 1027 if (!chchannel && c_oil && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
781a1745 1028 pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
dfbbce1d
DS
1029 }
1030 }
12e41d03
DL
1031 delete_on_noinfo(ch);
1032}
1033
1034void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
1035{
1036 int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
1037 int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
1038
1039 if (new_couldassert == old_couldassert)
1040 return;
1041
1042 if (PIM_DEBUG_PIM_EVENTS) {
eaa54bdb
DW
1043 char src_str[INET_ADDRSTRLEN];
1044 char grp_str[INET_ADDRSTRLEN];
4ed0af70
DS
1045 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1046 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
12e41d03
DL
1047 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
1048 __PRETTY_FUNCTION__,
1049 src_str, grp_str, ch->interface->name,
1050 old_couldassert, new_couldassert);
1051 }
1052
1053 if (new_couldassert) {
1054 /* CouldAssert(S,G,I) switched from FALSE to TRUE */
1055 PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
1056 }
1057 else {
1058 /* CouldAssert(S,G,I) switched from TRUE to FALSE */
1059 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
1060
1061 if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
1062 assert_action_a4(ch);
1063 }
1064 }
1065
1066 pim_ifchannel_update_my_assert_metric(ch);
1067}
1068
1069/*
1070 my_assert_metric may be affected by:
1071
1072 CouldAssert(S,G)
1073 pim_ifp->primary_address
1074 rpf->source_nexthop.mrib_metric_preference;
1075 rpf->source_nexthop.mrib_route_metric;
1076 */
1077void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
1078{
1079 struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch);
1080
1081 if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
1082 return;
1083
1084 if (PIM_DEBUG_PIM_EVENTS) {
eaa54bdb
DW
1085 char src_str[INET_ADDRSTRLEN];
1086 char grp_str[INET_ADDRSTRLEN];
1087 char old_addr_str[INET_ADDRSTRLEN];
1088 char new_addr_str[INET_ADDRSTRLEN];
4ed0af70
DS
1089 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1090 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
12e41d03
DL
1091 pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
1092 pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
1093 zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
1094 __PRETTY_FUNCTION__,
1095 src_str, grp_str, ch->interface->name,
1096 ch->ifassert_my_metric.rpt_bit_flag,
1097 ch->ifassert_my_metric.metric_preference,
1098 ch->ifassert_my_metric.route_metric,
1099 old_addr_str,
1100 my_metric_new.rpt_bit_flag,
1101 my_metric_new.metric_preference,
1102 my_metric_new.route_metric,
1103 new_addr_str);
1104 }
1105
1106 ch->ifassert_my_metric = my_metric_new;
1107
1108 if (pim_assert_metric_better(&ch->ifassert_my_metric,
1109 &ch->ifassert_winner_metric)) {
1110 assert_action_a5(ch);
1111 }
1112}
1113
1114void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
1115{
1116 int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
1117 int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
1118
1119 if (new_atd == old_atd)
1120 return;
1121
1122 if (PIM_DEBUG_PIM_EVENTS) {
eaa54bdb
DW
1123 char src_str[INET_ADDRSTRLEN];
1124 char grp_str[INET_ADDRSTRLEN];
4ed0af70
DS
1125 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1126 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
12e41d03
DL
1127 zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
1128 __PRETTY_FUNCTION__,
1129 src_str, grp_str, ch->interface->name,
1130 old_atd, new_atd);
1131 }
1132
1133 if (new_atd) {
1134 /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
1135 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
1136 }
1137 else {
1138 /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
1139 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
1140
1141 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1142 assert_action_a5(ch);
1143 }
1144 }
1145}
c8507a16
DS
1146
1147/*
1148 * If we have a new pim interface, check to
1149 * see if any of the pre-existing channels have
1150 * their upstream out that way and turn on forwarding
1151 * for that ifchannel then.
1152 */
1153void
1154pim_ifchannel_scan_forward_start (struct interface *new_ifp)
1155{
1156 struct listnode *ifnode;
1157 struct interface *ifp;
1158 struct pim_interface *new_pim_ifp = new_ifp->info;
1159
1160 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
1161 {
1162 struct pim_interface *loop_pim_ifp = ifp->info;
1163 struct listnode *ch_node;
1164 struct pim_ifchannel *ch;
1165
1166 if (!loop_pim_ifp)
1167 continue;
1168
1169 if (new_pim_ifp == loop_pim_ifp)
1170 continue;
1171
1172 for (ALL_LIST_ELEMENTS_RO (loop_pim_ifp->pim_ifchannel_list, ch_node, ch))
1173 {
1174 if (ch->ifjoin_state == PIM_IFJOIN_JOIN)
1175 {
1176 struct pim_upstream *up = ch->upstream;
1177 if ((!up->channel_oil) &&
1178 (up->rpf.source_nexthop.interface == new_ifp))
1179 pim_forward_start (ch);
1180 }
1181 }
1182 }
1183}
220d8a49
DS
1184
1185/*
1186 * Downstream per-interface (S,G,rpt) state machine
1187 * states that we need to move (S,G,rpt) items
1188 * into different states at the start of the
1189 * reception of a *,G join as well, when
1190 * we get End of Message
1191 */
1192void
1193pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom)
1194{
1195 struct pim_ifchannel *child;
1196 struct listnode *ch_node;
1197
1198 if (PIM_DEBUG_PIM_TRACE)
1199 zlog_debug ("%s: %s %s eom: %d", __PRETTY_FUNCTION__,
1200 pim_ifchannel_ifjoin_name(ch->ifjoin_state),
8bfb8b67 1201 ch->sg_str, eom);
220d8a49
DS
1202 if (!ch->sources)
1203 return;
1204
1205 for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child))
1206 {
1207 if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
1208 continue;
1209
1210 switch (child->ifjoin_state)
1405c852
DS
1211 {
1212 case PIM_IFJOIN_NOINFO:
1213 case PIM_IFJOIN_JOIN:
1214 break;
1215 case PIM_IFJOIN_PRUNE:
1216 if (!eom)
1217 child->ifjoin_state = PIM_IFJOIN_PRUNE_TMP;
1218 break;
1219 case PIM_IFJOIN_PRUNE_PENDING:
1220 if (!eom)
1221 child->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING_TMP;
1222 break;
1223 case PIM_IFJOIN_PRUNE_TMP:
1224 case PIM_IFJOIN_PRUNE_PENDING_TMP:
1225 if (eom)
1226 child->ifjoin_state = PIM_IFJOIN_NOINFO;
1227 break;
1228 }
220d8a49
DS
1229 }
1230}