]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_ifchannel.c
Merge pull request #7394 from donaldsharp/isis_uninited
[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:
48484e58 953 /*
954 * Transitions from Prune-Pending State (Receive Join)
955 * RFC 7761 Sec 4.5.2:
956 * The (S,G) downstream state machine on interface I
957 * transitions to the Join state. The Prune-Pending Timer is
958 * canceled (without triggering an expiry event). The
959 * Expiry Timer (ET) is restarted and is then set to the
960 * maximum of its current value and the HoldTime from the
961 * triggering Join/Prune message.
962 */
d62a17ae 963 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
877ebdf0 964
965 /* Check if SGRpt join Received */
966 if ((source_flags & PIM_ENCODE_RPT_BIT)
967 && (sg->src.s_addr != INADDR_ANY)) {
48484e58 968 /*
969 * Transitions from Prune-Pending State (Rcv SGRpt Join)
970 * RFC 7761 Sec 4.5.3:
971 * The (S,G,rpt) downstream state machine on interface
972 * I transitions to the NoInfo state.The ET and PPT are
973 * cancelled.
974 */
d62a17ae 975 THREAD_OFF(ch->t_ifjoin_expiry_timer);
15569c58 976 pim_ifchannel_ifjoin_switch(__func__, ch,
d62a17ae 977 PIM_IFJOIN_NOINFO);
48484e58 978 return;
979 }
980
981 pim_ifchannel_ifjoin_handler(ch, pim_ifp);
982
983 if (ch->t_ifjoin_expiry_timer) {
984 unsigned long remain = thread_timer_remain_second(
985 ch->t_ifjoin_expiry_timer);
986
987 if (remain > holdtime)
988 return;
94e3f3e5 989 }
48484e58 990
d62a17ae 991 break;
992 case PIM_IFJOIN_PRUNE_TMP:
993 break;
994 case PIM_IFJOIN_PRUNE_PENDING_TMP:
995 break;
996 }
997
998 if (holdtime != 0xFFFF) {
36417fcc
DS
999 thread_add_timer(router->master, on_ifjoin_expiry_timer, ch,
1000 holdtime, &ch->t_ifjoin_expiry_timer);
d62a17ae 1001 }
12e41d03
DL
1002}
1003
d62a17ae 1004void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
1005 struct prefix_sg *sg, uint8_t source_flags,
12e41d03
DL
1006 uint16_t holdtime)
1007{
d62a17ae 1008 struct pim_ifchannel *ch;
1009 struct pim_interface *pim_ifp;
1010 int jp_override_interval_msec;
1405c852 1011
d62a17ae 1012 if (nonlocal_upstream(0 /* prune */, ifp, upstream, sg, source_flags,
1013 holdtime)) {
1014 return;
1015 }
1016
1017 ch = pim_ifchannel_find(ifp, sg);
1018 if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) {
23fc858a 1019 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1020 zlog_debug(
41714081 1021 "%s: Received prune with no relevant ifchannel %s%s state: %d",
15569c58
DA
1022 __func__, ifp->name, pim_str_sg_dump(sg),
1023 source_flags);
d62a17ae 1024 return;
1025 }
1026
0885a9f1
DS
1027 ch = pim_ifchannel_add(ifp, sg, source_flags,
1028 PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
d62a17ae 1029
1030 pim_ifp = ifp->info;
1031
1032 switch (ch->ifjoin_state) {
1033 case PIM_IFJOIN_NOINFO:
1034 if (source_flags & PIM_ENCODE_RPT_BIT) {
1035 if (!(source_flags & PIM_ENCODE_WC_BIT))
1036 PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
1037
1038 ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
1039 if (listcount(pim_ifp->pim_neighbor_list) > 1)
1040 jp_override_interval_msec =
1041 pim_if_jp_override_interval_msec(ifp);
1042 else
1043 jp_override_interval_msec =
1044 0; /* schedule to expire immediately */
1045 /* If we called ifjoin_prune() directly instead, care
1046 should
1047 be taken not to use "ch" afterwards since it would be
1048 deleted. */
1049
1050 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
1051 THREAD_OFF(ch->t_ifjoin_expiry_timer);
1052 thread_add_timer_msec(
36417fcc
DS
1053 router->master, on_ifjoin_prune_pending_timer,
1054 ch, jp_override_interval_msec,
d62a17ae 1055 &ch->t_ifjoin_prune_pending_timer);
36417fcc
DS
1056 thread_add_timer(router->master, on_ifjoin_expiry_timer,
1057 ch, holdtime,
1058 &ch->t_ifjoin_expiry_timer);
9b29ea95
DS
1059 pim_upstream_update_join_desired(pim_ifp->pim,
1060 ch->upstream);
d62a17ae 1061 }
1062 break;
1063 case PIM_IFJOIN_PRUNE_PENDING:
1064 /* nothing to do */
1065 break;
1066 case PIM_IFJOIN_JOIN:
48484e58 1067 /*
1068 * The (S,G) downstream state machine on interface I
1069 * transitions to the Prune-Pending state. The
1070 * Prune-Pending Timer is started. It is set to the
1071 * J/P_Override_Interval(I) if the router has more than one
1072 * neighbor on that interface; otherwise, it is set to zero,
1073 * causing it to expire immediately.
1074 */
d62a17ae 1075
15569c58 1076 pim_ifchannel_ifjoin_switch(__func__, ch,
d62a17ae 1077 PIM_IFJOIN_PRUNE_PENDING);
1078
1079 if (listcount(pim_ifp->pim_neighbor_list) > 1)
1080 jp_override_interval_msec =
1081 pim_if_jp_override_interval_msec(ifp);
1082 else
1083 jp_override_interval_msec =
1084 0; /* schedule to expire immediately */
1085 /* If we called ifjoin_prune() directly instead, care should
1086 be taken not to use "ch" afterwards since it would be
1087 deleted. */
1088 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
36417fcc
DS
1089 thread_add_timer_msec(router->master,
1090 on_ifjoin_prune_pending_timer, ch,
d62a17ae 1091 jp_override_interval_msec,
1092 &ch->t_ifjoin_prune_pending_timer);
1093 break;
1094 case PIM_IFJOIN_PRUNE:
1095 if (source_flags & PIM_ENCODE_RPT_BIT) {
1096 THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
36417fcc
DS
1097 thread_add_timer(router->master, on_ifjoin_expiry_timer,
1098 ch, holdtime,
1099 &ch->t_ifjoin_expiry_timer);
d62a17ae 1100 }
1101 break;
1102 case PIM_IFJOIN_PRUNE_TMP:
1103 if (source_flags & PIM_ENCODE_RPT_BIT) {
1104 ch->ifjoin_state = PIM_IFJOIN_PRUNE;
1105 THREAD_OFF(ch->t_ifjoin_expiry_timer);
36417fcc
DS
1106 thread_add_timer(router->master, on_ifjoin_expiry_timer,
1107 ch, holdtime,
1108 &ch->t_ifjoin_expiry_timer);
d62a17ae 1109 }
1110 break;
1111 case PIM_IFJOIN_PRUNE_PENDING_TMP:
1112 if (source_flags & PIM_ENCODE_RPT_BIT) {
1113 ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
1114 THREAD_OFF(ch->t_ifjoin_expiry_timer);
36417fcc
DS
1115 thread_add_timer(router->master, on_ifjoin_expiry_timer,
1116 ch, holdtime,
1117 &ch->t_ifjoin_expiry_timer);
d62a17ae 1118 }
1119 break;
1120 }
12e41d03
DL
1121}
1122
d62a17ae 1123int pim_ifchannel_local_membership_add(struct interface *ifp,
448139e7 1124 struct prefix_sg *sg, bool is_vxlan)
12e41d03 1125{
d62a17ae 1126 struct pim_ifchannel *ch, *starch;
1127 struct pim_interface *pim_ifp;
43e40fdf 1128 struct pim_instance *pim;
448139e7 1129 int up_flags;
d62a17ae 1130
1131 /* PIM enabled on interface? */
1132 pim_ifp = ifp->info;
78b0c6bf
DS
1133 if (!pim_ifp) {
1134 if (PIM_DEBUG_EVENTS)
1135 zlog_debug("%s:%s Expected pim interface setup for %s",
5e81f5dd 1136 __func__, pim_str_sg_dump(sg), ifp->name);
d62a17ae 1137 return 0;
78b0c6bf
DS
1138 }
1139
1140 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
1141 if (PIM_DEBUG_EVENTS)
5e81f5dd
DS
1142 zlog_debug(
1143 "%s:%s PIM is not configured on this interface %s",
1144 __func__, pim_str_sg_dump(sg), ifp->name);
d62a17ae 1145 return 0;
78b0c6bf 1146 }
d62a17ae 1147
43e40fdf
DS
1148 pim = pim_ifp->pim;
1149
d62a17ae 1150 /* skip (*,G) ch creation if G is of type SSM */
1151 if (sg->src.s_addr == INADDR_ANY) {
6f439a70 1152 if (pim_is_grp_ssm(pim, sg->grp)) {
d62a17ae 1153 if (PIM_DEBUG_PIM_EVENTS)
1154 zlog_debug(
1155 "%s: local membership (S,G)=%s ignored as group is SSM",
5e81f5dd 1156 __func__, pim_str_sg_dump(sg));
d62a17ae 1157 return 1;
1158 }
1159 }
1160
17823cdd
DS
1161 /* vxlan term mroutes use ipmr-lo as local member to
1162 * pull down multicast vxlan tunnel traffic
1163 */
448139e7
AK
1164 up_flags = is_vxlan ? PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM :
1165 PIM_UPSTREAM_FLAG_MASK_SRC_IGMP;
1166 ch = pim_ifchannel_add(ifp, sg, 0, up_flags);
d62a17ae 1167
1168 ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
1169
1170 if (sg->src.s_addr == INADDR_ANY) {
9b29ea95 1171 struct pim_upstream *up = pim_upstream_find(pim, sg);
d62a17ae 1172 struct pim_upstream *child;
1173 struct listnode *up_node;
1174
1175 starch = ch;
1176
1177 for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
1178 if (PIM_DEBUG_EVENTS)
1179 zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
5e81f5dd
DS
1180 __FILE__, __func__, child->sg_str,
1181 ifp->name, up->sg_str);
d62a17ae 1182
1183 ch = pim_ifchannel_find(ifp, &child->sg);
1184 if (pim_upstream_evaluate_join_desired_interface(
1185 child, ch, starch)) {
1186 pim_channel_add_oif(child->channel_oil, ifp,
1b249e70
AK
1187 PIM_OIF_FLAG_PROTO_STAR,
1188 __func__);
a53a9b3e 1189 pim_upstream_update_join_desired(pim, child);
d62a17ae 1190 }
1191 }
1192
43e40fdf 1193 if (pim->spt.switchover == PIM_SPT_INFINITY) {
f88df3a6 1194 if (pim->spt.plist) {
d62a17ae 1195 struct prefix_list *plist = prefix_list_lookup(
43e40fdf 1196 AFI_IP, pim->spt.plist);
d62a17ae 1197 struct prefix g;
1198 g.family = AF_INET;
1199 g.prefixlen = IPV4_MAX_PREFIXLEN;
1200 g.u.prefix4 = up->sg.grp;
1201
1202 if (prefix_list_apply(plist, &g)
1203 == PREFIX_DENY) {
1204 pim_channel_add_oif(
43e40fdf 1205 up->channel_oil, pim->regiface,
1b249e70
AK
1206 PIM_OIF_FLAG_PROTO_IGMP,
1207 __func__);
d62a17ae 1208 }
1209 }
1210 } else
43e40fdf 1211 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
1212 PIM_OIF_FLAG_PROTO_IGMP,
1213 __func__);
d62a17ae 1214 }
1215
1216 return 1;
12e41d03
DL
1217}
1218
1219void pim_ifchannel_local_membership_del(struct interface *ifp,
4ed0af70 1220 struct prefix_sg *sg)
12e41d03 1221{
d62a17ae 1222 struct pim_ifchannel *starch, *ch, *orig;
1223 struct pim_interface *pim_ifp;
1224
1225 /* PIM enabled on interface? */
1226 pim_ifp = ifp->info;
1227 if (!pim_ifp)
1228 return;
1229 if (!PIM_IF_TEST_PIM(pim_ifp->options))
1230 return;
1231
1232 orig = ch = pim_ifchannel_find(ifp, sg);
1233 if (!ch)
1234 return;
d62a17ae 1235 ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
1236
1237 if (sg->src.s_addr == INADDR_ANY) {
9b29ea95 1238 struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg);
d62a17ae 1239 struct pim_upstream *child;
1240 struct listnode *up_node, *up_nnode;
1241
1242 starch = ch;
1243
1244 for (ALL_LIST_ELEMENTS(up->sources, up_node, up_nnode, child)) {
1245 struct channel_oil *c_oil = child->channel_oil;
1246 struct pim_ifchannel *chchannel =
1247 pim_ifchannel_find(ifp, &child->sg);
dc7204b7
A
1248
1249 pim_ifp = ifp->info;
d62a17ae 1250
1251 if (PIM_DEBUG_EVENTS)
1252 zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
5e81f5dd
DS
1253 __FILE__, __func__, up->sg_str,
1254 ifp->name, child->sg_str);
d62a17ae 1255
1256 ch = pim_ifchannel_find(ifp, &child->sg);
d62a17ae 1257 /*
1258 * If the S,G has no if channel and the c_oil still
1259 * has output here then the *,G was supplying the
1260 * implied
1261 * if channel. So remove it.
1262 */
1537a668
AK
1263 if (!pim_upstream_evaluate_join_desired_interface(
1264 child, ch, starch) ||
1265 (!chchannel &&
1266 c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])) {
1267 pim_channel_del_inherited_oif(c_oil, ifp,
1268 __func__);
1269 }
d62a17ae 1270
1271 /* Child node removal/ref count-- will happen as part of
1272 * parent' delete_no_info */
1273 }
1274 }
1275 delete_on_noinfo(orig);
12e41d03
DL
1276}
1277
1278void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
1279{
d62a17ae 1280 int old_couldassert =
1281 PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags));
1282 int new_couldassert =
1283 PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch));
1284
1285 if (new_couldassert == old_couldassert)
1286 return;
1287
1288 if (PIM_DEBUG_PIM_EVENTS) {
1289 char src_str[INET_ADDRSTRLEN];
1290 char grp_str[INET_ADDRSTRLEN];
1291 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1292 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
1293 zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
15569c58
DA
1294 __func__, src_str, grp_str, ch->interface->name,
1295 old_couldassert, new_couldassert);
d62a17ae 1296 }
1297
1298 if (new_couldassert) {
2951a7a4 1299 /* CouldAssert(S,G,I) switched from false to true */
d62a17ae 1300 PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
1301 } else {
2951a7a4 1302 /* CouldAssert(S,G,I) switched from true to false */
d62a17ae 1303 PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
1304
1305 if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
1306 assert_action_a4(ch);
1307 }
1308 }
1309
1310 pim_ifchannel_update_my_assert_metric(ch);
12e41d03
DL
1311}
1312
1313/*
1314 my_assert_metric may be affected by:
1315
1316 CouldAssert(S,G)
1317 pim_ifp->primary_address
1318 rpf->source_nexthop.mrib_metric_preference;
1319 rpf->source_nexthop.mrib_route_metric;
1320 */
1321void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
1322{
d62a17ae 1323 struct pim_assert_metric my_metric_new =
1324 pim_macro_ch_my_assert_metric_eval(ch);
1325
1326 if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric))
1327 return;
1328
1329 if (PIM_DEBUG_PIM_EVENTS) {
1330 char src_str[INET_ADDRSTRLEN];
1331 char grp_str[INET_ADDRSTRLEN];
1332 char old_addr_str[INET_ADDRSTRLEN];
1333 char new_addr_str[INET_ADDRSTRLEN];
1334 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1335 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
1336 pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address,
1337 old_addr_str, sizeof(old_addr_str));
1338 pim_inet4_dump("<new_addr?>", my_metric_new.ip_address,
1339 new_addr_str, sizeof(new_addr_str));
1340 zlog_debug(
1341 "%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
15569c58 1342 __func__, src_str, grp_str, ch->interface->name,
d62a17ae 1343 ch->ifassert_my_metric.rpt_bit_flag,
1344 ch->ifassert_my_metric.metric_preference,
1345 ch->ifassert_my_metric.route_metric, old_addr_str,
1346 my_metric_new.rpt_bit_flag,
1347 my_metric_new.metric_preference,
1348 my_metric_new.route_metric, new_addr_str);
1349 }
1350
1351 ch->ifassert_my_metric = my_metric_new;
1352
1353 if (pim_assert_metric_better(&ch->ifassert_my_metric,
1354 &ch->ifassert_winner_metric)) {
1355 assert_action_a5(ch);
1356 }
12e41d03
DL
1357}
1358
1359void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
1360{
d62a17ae 1361 int old_atd = PIM_FORCE_BOOLEAN(
1362 PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags));
1363 int new_atd =
1364 PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch));
1365
1366 if (new_atd == old_atd)
1367 return;
1368
1369 if (PIM_DEBUG_PIM_EVENTS) {
1370 char src_str[INET_ADDRSTRLEN];
1371 char grp_str[INET_ADDRSTRLEN];
1372 pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
1373 pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
1374 zlog_debug(
1375 "%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
15569c58
DA
1376 __func__, src_str, grp_str, ch->interface->name,
1377 old_atd, new_atd);
d62a17ae 1378 }
1379
1380 if (new_atd) {
2951a7a4 1381 /* AssertTrackingDesired(S,G,I) switched from false to true */
d62a17ae 1382 PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
1383 } else {
2951a7a4 1384 /* AssertTrackingDesired(S,G,I) switched from true to false */
d62a17ae 1385 PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
1386
1387 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1388 assert_action_a5(ch);
1389 }
1390 }
12e41d03 1391}
c8507a16
DS
1392
1393/*
1394 * If we have a new pim interface, check to
1395 * see if any of the pre-existing channels have
1396 * their upstream out that way and turn on forwarding
1397 * for that ifchannel then.
1398 */
d62a17ae 1399void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
c8507a16 1400{
d62a17ae 1401 struct pim_interface *new_pim_ifp = new_ifp->info;
f88df3a6 1402 struct pim_instance *pim = new_pim_ifp->pim;
ad7b74c4 1403 struct interface *ifp;
d62a17ae 1404
451fda4f 1405 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1406 struct pim_interface *loop_pim_ifp = ifp->info;
d62a17ae 1407 struct pim_ifchannel *ch;
1408
1409 if (!loop_pim_ifp)
1410 continue;
1411
1412 if (new_pim_ifp == loop_pim_ifp)
1413 continue;
1414
a2addae8 1415 RB_FOREACH (ch, pim_ifchannel_rb, &loop_pim_ifp->ifchannel_rb) {
d62a17ae 1416 if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
1417 struct pim_upstream *up = ch->upstream;
1418 if ((!up->channel_oil)
1419 && (up->rpf.source_nexthop
1420 .interface == new_ifp))
1421 pim_forward_start(ch);
1422 }
1423 }
1424 }
c8507a16 1425}
220d8a49
DS
1426
1427/*
1428 * Downstream per-interface (S,G,rpt) state machine
1429 * states that we need to move (S,G,rpt) items
1430 * into different states at the start of the
1431 * reception of a *,G join as well, when
1432 * we get End of Message
1433 */
d62a17ae 1434void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
c206937b 1435 uint8_t join)
220d8a49 1436{
ca6cb21b 1437 bool send_upstream_starg = false;
d62a17ae 1438 struct pim_ifchannel *child;
37736d08 1439 struct listnode *ch_node, *nch_node;
c206937b
DS
1440 struct pim_instance *pim =
1441 ((struct pim_interface *)ch->interface->info)->pim;
ca6cb21b 1442 struct pim_upstream *starup = ch->upstream;
d62a17ae 1443
1444 if (PIM_DEBUG_PIM_TRACE)
1445 zlog_debug(
5e81f5dd 1446 "%s: %s %s eom: %d join %u", __func__,
d62a17ae 1447 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
1448 ch->sg_str, eom, join);
1449 if (!ch->sources)
1450 return;
1451
37736d08 1452 for (ALL_LIST_ELEMENTS(ch->sources, ch_node, nch_node, child)) {
d62a17ae 1453 if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
1454 continue;
1455
1456 switch (child->ifjoin_state) {
1457 case PIM_IFJOIN_NOINFO:
1458 case PIM_IFJOIN_JOIN:
1459 break;
1460 case PIM_IFJOIN_PRUNE:
1461 if (!eom)
1462 child->ifjoin_state = PIM_IFJOIN_PRUNE_TMP;
1463 break;
1464 case PIM_IFJOIN_PRUNE_PENDING:
1465 if (!eom)
1466 child->ifjoin_state =
1467 PIM_IFJOIN_PRUNE_PENDING_TMP;
1468 break;
1469 case PIM_IFJOIN_PRUNE_TMP:
1470 case PIM_IFJOIN_PRUNE_PENDING_TMP:
37736d08
DS
1471 if (!eom)
1472 break;
1473
1474 if (child->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING_TMP)
1475 THREAD_OFF(child->t_ifjoin_prune_pending_timer);
1476 THREAD_OFF(child->t_ifjoin_expiry_timer);
37736d08
DS
1477
1478 PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
1479 child->ifjoin_state = PIM_IFJOIN_NOINFO;
1480
0cdbb2cf
SP
1481 if ((I_am_RP(pim, child->sg.grp)) &&
1482 (!pim_upstream_empty_inherited_olist(
1483 child->upstream))) {
37736d08
DS
1484 pim_channel_add_oif(
1485 child->upstream->channel_oil,
1b249e70
AK
1486 ch->interface, PIM_OIF_FLAG_PROTO_STAR,
1487 __func__);
a53a9b3e
AK
1488 pim_upstream_update_join_desired(pim,
1489 child->upstream);
c206937b 1490 }
ca6cb21b 1491 send_upstream_starg = true;
37736d08
DS
1492
1493 delete_on_noinfo(child);
d62a17ae 1494 break;
1495 }
1405c852 1496 }
ca6cb21b
DS
1497
1498 if (send_upstream_starg)
1499 pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
220d8a49 1500}
a625e937 1501
d8b87afe 1502unsigned int pim_ifchannel_hash_key(const void *arg)
a625e937 1503{
d8b87afe 1504 const struct pim_ifchannel *ch = arg;
a625e937 1505
d62a17ae 1506 return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
a625e937 1507}