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