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