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