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