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