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