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