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