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