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