]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Create some infrastructure code for RST(S,G) and KAT(S,G)
[mirror_frr.git] / pimd / pim_upstream.c
CommitLineData
12e41d03
DL
1/*
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "zebra/rib.h"
26
27#include "log.h"
28#include "zclient.h"
29#include "memory.h"
30#include "thread.h"
31#include "linklist.h"
32
33#include "pimd.h"
34#include "pim_pim.h"
35#include "pim_str.h"
36#include "pim_time.h"
37#include "pim_iface.h"
38#include "pim_join.h"
39#include "pim_zlookup.h"
40#include "pim_upstream.h"
41#include "pim_ifchannel.h"
42#include "pim_neighbor.h"
43#include "pim_rpf.h"
44#include "pim_zebra.h"
45#include "pim_oil.h"
46#include "pim_macro.h"
8f5f5e91 47#include "pim_rp.h"
12e41d03
DL
48
49static void join_timer_start(struct pim_upstream *up);
50static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
51
52void pim_upstream_free(struct pim_upstream *up)
53{
54 XFREE(MTYPE_PIM_UPSTREAM, up);
55}
56
57static void upstream_channel_oil_detach(struct pim_upstream *up)
58{
59 if (up->channel_oil) {
60 pim_channel_oil_del(up->channel_oil);
61 up->channel_oil = 0;
62 }
63}
64
65void pim_upstream_delete(struct pim_upstream *up)
66{
67 THREAD_OFF(up->t_join_timer);
68
69 upstream_channel_oil_detach(up);
70
71 /*
72 notice that listnode_delete() can't be moved
73 into pim_upstream_free() because the later is
74 called by list_delete_all_node()
75 */
76 listnode_delete(qpim_upstream_list, up);
77
78 pim_upstream_free(up);
79}
80
81static void send_join(struct pim_upstream *up)
82{
83 zassert(up->join_state == PIM_UPSTREAM_JOINED);
84
85
86 if (PIM_DEBUG_PIM_TRACE) {
87 if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
88 char src_str[100];
89 char grp_str[100];
90 char rpf_str[100];
91 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
92 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
93 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
94 zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s",
95 __PRETTY_FUNCTION__,
96 src_str, grp_str, rpf_str);
97 /* warning only */
98 }
99 }
100
101 /* send Join(S,G) to the current upstream neighbor */
102 pim_joinprune_send(up->rpf.source_nexthop.interface,
103 up->rpf.rpf_addr,
104 up->source_addr,
105 up->group_addr,
106 1 /* join */);
107}
108
109static int on_join_timer(struct thread *t)
110{
111 struct pim_upstream *up;
112
113 zassert(t);
114 up = THREAD_ARG(t);
115 zassert(up);
116
117 send_join(up);
118
4a4c4a07 119 up->t_join_timer = NULL;
12e41d03
DL
120 join_timer_start(up);
121
122 return 0;
123}
124
125static void join_timer_start(struct pim_upstream *up)
126{
127 if (PIM_DEBUG_PIM_EVENTS) {
128 char src_str[100];
129 char grp_str[100];
130 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
131 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
132 zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)",
133 __PRETTY_FUNCTION__,
134 qpim_t_periodic,
135 src_str, grp_str);
136 }
137
138 zassert(!up->t_join_timer);
139
140 THREAD_TIMER_ON(master, up->t_join_timer,
141 on_join_timer,
142 up, qpim_t_periodic);
143}
144
145void pim_upstream_join_timer_restart(struct pim_upstream *up)
146{
147 THREAD_OFF(up->t_join_timer);
148 join_timer_start(up);
149}
150
151static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
152 int interval_msec)
153{
154 if (PIM_DEBUG_PIM_EVENTS) {
155 char src_str[100];
156 char grp_str[100];
157 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
158 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
159 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)",
160 __PRETTY_FUNCTION__,
161 interval_msec,
162 src_str, grp_str);
163 }
164
165 THREAD_OFF(up->t_join_timer);
166 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
167 on_join_timer,
168 up, interval_msec);
169}
170
171void pim_upstream_join_suppress(struct pim_upstream *up,
172 struct in_addr rpf_addr,
173 int holdtime)
174{
175 long t_joinsuppress_msec;
176 long join_timer_remain_msec;
177
178 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
179 1000 * holdtime);
180
181 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
182
183 if (PIM_DEBUG_PIM_TRACE) {
184 char src_str[100];
185 char grp_str[100];
186 char rpf_str[100];
187 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
188 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
189 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
190 zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
191 __FILE__, __PRETTY_FUNCTION__,
192 src_str, grp_str,
193 rpf_str,
194 join_timer_remain_msec, t_joinsuppress_msec);
195 }
196
197 if (join_timer_remain_msec < t_joinsuppress_msec) {
198 if (PIM_DEBUG_PIM_TRACE) {
199 char src_str[100];
200 char grp_str[100];
201 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
202 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
203 zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec",
204 __FILE__, __PRETTY_FUNCTION__,
205 src_str, grp_str, t_joinsuppress_msec);
206 }
207
208 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
209 }
210}
211
212void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
213 struct pim_upstream *up,
214 struct in_addr rpf_addr)
215{
216 long join_timer_remain_msec;
217 int t_override_msec;
218
219 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
220 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
221
222 if (PIM_DEBUG_PIM_TRACE) {
223 char src_str[100];
224 char grp_str[100];
225 char rpf_str[100];
226 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
227 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
228 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
229 zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec",
230 debug_label,
231 src_str, grp_str, rpf_str,
232 join_timer_remain_msec, t_override_msec);
233 }
234
235 if (join_timer_remain_msec > t_override_msec) {
236 if (PIM_DEBUG_PIM_TRACE) {
237 char src_str[100];
238 char grp_str[100];
239 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
240 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
241 zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec",
242 debug_label,
243 src_str, grp_str,
244 t_override_msec);
245 }
246
247 pim_upstream_join_timer_restart_msec(up, t_override_msec);
248 }
249}
250
251static void forward_on(struct pim_upstream *up)
252{
253 struct listnode *ifnode;
254 struct listnode *ifnextnode;
255 struct listnode *chnode;
256 struct listnode *chnextnode;
257 struct interface *ifp;
258 struct pim_interface *pim_ifp;
259 struct pim_ifchannel *ch;
260
261 /* scan all interfaces */
469351b3 262 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
263 pim_ifp = ifp->info;
264 if (!pim_ifp)
265 continue;
266
267 /* scan per-interface (S,G) state */
268 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
269
270 if (ch->upstream != up)
271 continue;
272
273 if (pim_macro_chisin_oiflist(ch))
274 pim_forward_start(ch);
275
276 } /* scan iface channel list */
277 } /* scan iflist */
278}
279
280static void forward_off(struct pim_upstream *up)
281{
282 struct listnode *ifnode;
283 struct listnode *ifnextnode;
284 struct listnode *chnode;
285 struct listnode *chnextnode;
286 struct interface *ifp;
287 struct pim_interface *pim_ifp;
288 struct pim_ifchannel *ch;
289
290 /* scan all interfaces */
469351b3 291 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
292 pim_ifp = ifp->info;
293 if (!pim_ifp)
294 continue;
295
296 /* scan per-interface (S,G) state */
297 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
298
299 if (ch->upstream != up)
300 continue;
301
302 pim_forward_stop(ch);
303
304 } /* scan iface channel list */
305 } /* scan iflist */
306}
307
308static void pim_upstream_switch(struct pim_upstream *up,
309 enum pim_upstream_state new_state)
310{
311 enum pim_upstream_state old_state = up->join_state;
312
313 zassert(old_state != new_state);
314
315 up->join_state = new_state;
316 up->state_transition = pim_time_monotonic_sec();
317
318 if (PIM_DEBUG_PIM_EVENTS) {
319 char src_str[100];
320 char grp_str[100];
321 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
322 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
323 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
324 __PRETTY_FUNCTION__,
325 ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
326 src_str, grp_str);
327 }
328
329 pim_upstream_update_assert_tracking_desired(up);
330
331 if (new_state == PIM_UPSTREAM_JOINED) {
332 forward_on(up);
333 send_join(up);
334 join_timer_start(up);
335 }
336 else {
337 forward_off(up);
338 pim_joinprune_send(up->rpf.source_nexthop.interface,
339 up->rpf.rpf_addr,
340 up->source_addr,
341 up->group_addr,
342 0 /* prune */);
343 zassert(up->t_join_timer);
344 THREAD_OFF(up->t_join_timer);
345 }
346
347}
348
8f5f5e91 349
12e41d03
DL
350static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
351 struct in_addr group_addr)
352{
353 struct pim_upstream *up;
2f702571 354 enum pim_rpf_result rpf_result;
12e41d03
DL
355
356 up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
357 if (!up) {
358 zlog_err("%s: PIM XMALLOC(%zu) failure",
359 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 360 return NULL;
12e41d03
DL
361 }
362
363 up->source_addr = source_addr;
8f5f5e91
DS
364 if (!pim_rp_set_upstream_addr (&up->upstream_addr, source_addr))
365 {
366 if (PIM_DEBUG_PIM_TRACE)
367 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
368
369 XFREE (MTYPE_PIM_UPSTREAM, up);
370 return NULL;
371 }
372
12e41d03
DL
373 up->group_addr = group_addr;
374 up->flags = 0;
375 up->ref_count = 1;
4a4c4a07
DS
376 up->t_join_timer = NULL;
377 up->t_ka_timer = NULL;
12e41d03
DL
378 up->join_state = 0;
379 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 380 up->channel_oil = NULL;
d99764f6 381 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
12e41d03
DL
382
383 up->rpf.source_nexthop.interface = 0;
384 up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
385 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
386 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
387 up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
388
2f702571
DS
389 rpf_result = pim_rpf_update(up, 0);
390 if (rpf_result == PIM_RPF_FAILURE) {
391 XFREE(MTYPE_PIM_UPSTREAM, up);
392 return NULL;
393 }
12e41d03
DL
394
395 listnode_add(qpim_upstream_list, up);
396
397 return up;
398}
399
400struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
401 struct in_addr group_addr)
402{
403 struct listnode *up_node;
404 struct pim_upstream *up;
405
406 for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
407 if (
408 (source_addr.s_addr == up->source_addr.s_addr) &&
409 (group_addr.s_addr == up->group_addr.s_addr)
410 ) {
411 return up;
412 }
413 }
414
415 return 0;
416}
417
418struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
419 struct in_addr group_addr)
420{
421 struct pim_upstream *up;
422
423 up = pim_upstream_find(source_addr, group_addr);
424 if (up) {
425 ++up->ref_count;
426 }
427 else {
428 up = pim_upstream_new(source_addr, group_addr);
429 }
430
431 return up;
432}
433
434void pim_upstream_del(struct pim_upstream *up)
435{
436 --up->ref_count;
437
438 if (up->ref_count < 1) {
439 pim_upstream_delete(up);
440 }
441}
442
443/*
444 Evaluate JoinDesired(S,G):
445
446 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
447 in the set:
448
449 inherited_olist(S,G) =
450 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
451
452 JoinDesired(S,G) may be affected by changes in the following:
453
454 pim_ifp->primary_address
455 pim_ifp->pim_dr_addr
456 ch->ifassert_winner_metric
457 ch->ifassert_winner
458 ch->local_ifmembership
459 ch->ifjoin_state
460 ch->upstream->rpf.source_nexthop.mrib_metric_preference
461 ch->upstream->rpf.source_nexthop.mrib_route_metric
462 ch->upstream->rpf.source_nexthop.interface
463
464 See also pim_upstream_update_join_desired() below.
465 */
466int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
467{
468 struct listnode *ifnode;
469 struct listnode *ifnextnode;
470 struct listnode *chnode;
471 struct listnode *chnextnode;
472 struct interface *ifp;
473 struct pim_interface *pim_ifp;
474 struct pim_ifchannel *ch;
475
476 /* scan all interfaces */
469351b3 477 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
478 pim_ifp = ifp->info;
479 if (!pim_ifp)
480 continue;
481
482 /* scan per-interface (S,G) state */
483 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
484 if (ch->upstream != up)
485 continue;
486
487 if (pim_macro_ch_lost_assert(ch))
488 continue; /* keep searching */
489
490 if (pim_macro_chisin_joins_or_include(ch))
491 return 1; /* true */
492 } /* scan iface channel list */
493 } /* scan iflist */
494
495 return 0; /* false */
496}
497
498/*
499 See also pim_upstream_evaluate_join_desired() above.
500*/
501void pim_upstream_update_join_desired(struct pim_upstream *up)
502{
503 int was_join_desired; /* boolean */
504 int is_join_desired; /* boolean */
505
506 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
507
508 is_join_desired = pim_upstream_evaluate_join_desired(up);
509 if (is_join_desired)
510 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
511 else
512 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
513
514 /* switched from false to true */
515 if (is_join_desired && !was_join_desired) {
516 zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
517 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
518 return;
519 }
520
521 /* switched from true to false */
522 if (!is_join_desired && was_join_desired) {
523 zassert(up->join_state == PIM_UPSTREAM_JOINED);
524 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
525 return;
526 }
527}
528
529/*
530 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
531 Transitions from Joined State
532 RPF'(S,G) GenID changes
533
534 The upstream (S,G) state machine remains in Joined state. If the
535 Join Timer is set to expire in more than t_override seconds, reset
536 it so that it expires after t_override seconds.
537*/
538void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
539{
540 struct listnode *up_node;
541 struct listnode *up_nextnode;
542 struct pim_upstream *up;
543
544 /*
545 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
546 */
547 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
548
549 if (PIM_DEBUG_PIM_TRACE) {
550 char neigh_str[100];
551 char src_str[100];
552 char grp_str[100];
553 char rpf_addr_str[100];
554 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
555 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
556 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
557 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
558 zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
559 __PRETTY_FUNCTION__,
560 neigh_str, src_str, grp_str,
561 up->join_state == PIM_UPSTREAM_JOINED,
562 rpf_addr_str);
563 }
564
565 /* consider only (S,G) upstream in Joined state */
566 if (up->join_state != PIM_UPSTREAM_JOINED)
567 continue;
568
569 /* match RPF'(S,G)=neigh_addr */
570 if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
571 continue;
572
573 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
574 up, neigh_addr);
575 }
576}
577
578
579void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
580 struct interface *old_rpf_ifp)
581{
582 struct listnode *ifnode;
583 struct listnode *ifnextnode;
584 struct interface *ifp;
585
586 /* scan all interfaces */
469351b3 587 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
588 struct listnode *chnode;
589 struct listnode *chnextnode;
590 struct pim_ifchannel *ch;
591 struct pim_interface *pim_ifp;
592
593 pim_ifp = ifp->info;
594 if (!pim_ifp)
595 continue;
596
597 /* search all ifchannels */
598 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
599 if (ch->upstream != up)
600 continue;
601
602 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
603 if (
604 /* RPF_interface(S) was NOT I */
605 (old_rpf_ifp == ch->interface)
606 &&
607 /* RPF_interface(S) stopped being I */
608 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
609 ) {
610 assert_action_a5(ch);
611 }
612 } /* PIM_IFASSERT_I_AM_LOSER */
613
614 pim_ifchannel_update_assert_tracking_desired(ch);
615 }
616 }
617}
618
619void pim_upstream_update_could_assert(struct pim_upstream *up)
620{
621 struct listnode *ifnode;
622 struct listnode *ifnextnode;
623 struct listnode *chnode;
624 struct listnode *chnextnode;
625 struct interface *ifp;
626 struct pim_interface *pim_ifp;
627 struct pim_ifchannel *ch;
628
629 /* scan all interfaces */
469351b3 630 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
631 pim_ifp = ifp->info;
632 if (!pim_ifp)
633 continue;
634
635 /* scan per-interface (S,G) state */
636 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
637
638 if (ch->upstream != up)
639 continue;
640
641 pim_ifchannel_update_could_assert(ch);
642
643 } /* scan iface channel list */
644 } /* scan iflist */
645}
646
647void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
648{
649 struct listnode *ifnode;
650 struct listnode *ifnextnode;
651 struct listnode *chnode;
652 struct listnode *chnextnode;
653 struct interface *ifp;
654 struct pim_interface *pim_ifp;
655 struct pim_ifchannel *ch;
656
657 /* scan all interfaces */
469351b3 658 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
659 pim_ifp = ifp->info;
660 if (!pim_ifp)
661 continue;
662
663 /* scan per-interface (S,G) state */
664 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
665
666 if (ch->upstream != up)
667 continue;
668
669 pim_ifchannel_update_my_assert_metric(ch);
670
671 } /* scan iface channel list */
672 } /* scan iflist */
673}
674
675static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
676{
677 struct listnode *ifnode;
678 struct listnode *ifnextnode;
679 struct listnode *chnode;
680 struct listnode *chnextnode;
681 struct interface *ifp;
682 struct pim_interface *pim_ifp;
683 struct pim_ifchannel *ch;
684
685 /* scan all interfaces */
469351b3 686 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
687 pim_ifp = ifp->info;
688 if (!pim_ifp)
689 continue;
690
691 /* scan per-interface (S,G) state */
692 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
693
694 if (ch->upstream != up)
695 continue;
696
697 pim_ifchannel_update_assert_tracking_desired(ch);
698
699 } /* scan iface channel list */
700 } /* scan iflist */
701}