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