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