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