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