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