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