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