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