]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Start work for handling of register command
[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
119 up->t_join_timer = 0;
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;
376 up->t_join_timer = 0;
377 up->join_state = 0;
378 up->state_transition = pim_time_monotonic_sec();
379 up->channel_oil = 0;
d99764f6 380 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
12e41d03
DL
381
382 up->rpf.source_nexthop.interface = 0;
383 up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
384 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
385 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
386 up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
387
2f702571
DS
388 rpf_result = pim_rpf_update(up, 0);
389 if (rpf_result == PIM_RPF_FAILURE) {
390 XFREE(MTYPE_PIM_UPSTREAM, up);
391 return NULL;
392 }
12e41d03
DL
393
394 listnode_add(qpim_upstream_list, up);
395
396 return up;
397}
398
399struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
400 struct in_addr group_addr)
401{
402 struct listnode *up_node;
403 struct pim_upstream *up;
404
405 for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
406 if (
407 (source_addr.s_addr == up->source_addr.s_addr) &&
408 (group_addr.s_addr == up->group_addr.s_addr)
409 ) {
410 return up;
411 }
412 }
413
414 return 0;
415}
416
417struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
418 struct in_addr group_addr)
419{
420 struct pim_upstream *up;
421
422 up = pim_upstream_find(source_addr, group_addr);
423 if (up) {
424 ++up->ref_count;
425 }
426 else {
427 up = pim_upstream_new(source_addr, group_addr);
428 }
429
430 return up;
431}
432
433void pim_upstream_del(struct pim_upstream *up)
434{
435 --up->ref_count;
436
437 if (up->ref_count < 1) {
438 pim_upstream_delete(up);
439 }
440}
441
442/*
443 Evaluate JoinDesired(S,G):
444
445 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
446 in the set:
447
448 inherited_olist(S,G) =
449 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
450
451 JoinDesired(S,G) may be affected by changes in the following:
452
453 pim_ifp->primary_address
454 pim_ifp->pim_dr_addr
455 ch->ifassert_winner_metric
456 ch->ifassert_winner
457 ch->local_ifmembership
458 ch->ifjoin_state
459 ch->upstream->rpf.source_nexthop.mrib_metric_preference
460 ch->upstream->rpf.source_nexthop.mrib_route_metric
461 ch->upstream->rpf.source_nexthop.interface
462
463 See also pim_upstream_update_join_desired() below.
464 */
465int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
466{
467 struct listnode *ifnode;
468 struct listnode *ifnextnode;
469 struct listnode *chnode;
470 struct listnode *chnextnode;
471 struct interface *ifp;
472 struct pim_interface *pim_ifp;
473 struct pim_ifchannel *ch;
474
475 /* scan all interfaces */
469351b3 476 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
477 pim_ifp = ifp->info;
478 if (!pim_ifp)
479 continue;
480
481 /* scan per-interface (S,G) state */
482 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
483 if (ch->upstream != up)
484 continue;
485
486 if (pim_macro_ch_lost_assert(ch))
487 continue; /* keep searching */
488
489 if (pim_macro_chisin_joins_or_include(ch))
490 return 1; /* true */
491 } /* scan iface channel list */
492 } /* scan iflist */
493
494 return 0; /* false */
495}
496
497/*
498 See also pim_upstream_evaluate_join_desired() above.
499*/
500void pim_upstream_update_join_desired(struct pim_upstream *up)
501{
502 int was_join_desired; /* boolean */
503 int is_join_desired; /* boolean */
504
505 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
506
507 is_join_desired = pim_upstream_evaluate_join_desired(up);
508 if (is_join_desired)
509 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
510 else
511 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
512
513 /* switched from false to true */
514 if (is_join_desired && !was_join_desired) {
515 zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
516 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
517 return;
518 }
519
520 /* switched from true to false */
521 if (!is_join_desired && was_join_desired) {
522 zassert(up->join_state == PIM_UPSTREAM_JOINED);
523 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
524 return;
525 }
526}
527
528/*
529 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
530 Transitions from Joined State
531 RPF'(S,G) GenID changes
532
533 The upstream (S,G) state machine remains in Joined state. If the
534 Join Timer is set to expire in more than t_override seconds, reset
535 it so that it expires after t_override seconds.
536*/
537void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
538{
539 struct listnode *up_node;
540 struct listnode *up_nextnode;
541 struct pim_upstream *up;
542
543 /*
544 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
545 */
546 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
547
548 if (PIM_DEBUG_PIM_TRACE) {
549 char neigh_str[100];
550 char src_str[100];
551 char grp_str[100];
552 char rpf_addr_str[100];
553 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
554 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
555 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
556 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
557 zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
558 __PRETTY_FUNCTION__,
559 neigh_str, src_str, grp_str,
560 up->join_state == PIM_UPSTREAM_JOINED,
561 rpf_addr_str);
562 }
563
564 /* consider only (S,G) upstream in Joined state */
565 if (up->join_state != PIM_UPSTREAM_JOINED)
566 continue;
567
568 /* match RPF'(S,G)=neigh_addr */
569 if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
570 continue;
571
572 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
573 up, neigh_addr);
574 }
575}
576
577
578void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
579 struct interface *old_rpf_ifp)
580{
581 struct listnode *ifnode;
582 struct listnode *ifnextnode;
583 struct interface *ifp;
584
585 /* scan all interfaces */
469351b3 586 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
587 struct listnode *chnode;
588 struct listnode *chnextnode;
589 struct pim_ifchannel *ch;
590 struct pim_interface *pim_ifp;
591
592 pim_ifp = ifp->info;
593 if (!pim_ifp)
594 continue;
595
596 /* search all ifchannels */
597 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
598 if (ch->upstream != up)
599 continue;
600
601 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
602 if (
603 /* RPF_interface(S) was NOT I */
604 (old_rpf_ifp == ch->interface)
605 &&
606 /* RPF_interface(S) stopped being I */
607 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
608 ) {
609 assert_action_a5(ch);
610 }
611 } /* PIM_IFASSERT_I_AM_LOSER */
612
613 pim_ifchannel_update_assert_tracking_desired(ch);
614 }
615 }
616}
617
618void pim_upstream_update_could_assert(struct pim_upstream *up)
619{
620 struct listnode *ifnode;
621 struct listnode *ifnextnode;
622 struct listnode *chnode;
623 struct listnode *chnextnode;
624 struct interface *ifp;
625 struct pim_interface *pim_ifp;
626 struct pim_ifchannel *ch;
627
628 /* scan all interfaces */
469351b3 629 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
630 pim_ifp = ifp->info;
631 if (!pim_ifp)
632 continue;
633
634 /* scan per-interface (S,G) state */
635 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
636
637 if (ch->upstream != up)
638 continue;
639
640 pim_ifchannel_update_could_assert(ch);
641
642 } /* scan iface channel list */
643 } /* scan iflist */
644}
645
646void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
647{
648 struct listnode *ifnode;
649 struct listnode *ifnextnode;
650 struct listnode *chnode;
651 struct listnode *chnextnode;
652 struct interface *ifp;
653 struct pim_interface *pim_ifp;
654 struct pim_ifchannel *ch;
655
656 /* scan all interfaces */
469351b3 657 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
658 pim_ifp = ifp->info;
659 if (!pim_ifp)
660 continue;
661
662 /* scan per-interface (S,G) state */
663 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
664
665 if (ch->upstream != up)
666 continue;
667
668 pim_ifchannel_update_my_assert_metric(ch);
669
670 } /* scan iface channel list */
671 } /* scan iflist */
672}
673
674static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
675{
676 struct listnode *ifnode;
677 struct listnode *ifnextnode;
678 struct listnode *chnode;
679 struct listnode *chnextnode;
680 struct interface *ifp;
681 struct pim_interface *pim_ifp;
682 struct pim_ifchannel *ch;
683
684 /* scan all interfaces */
469351b3 685 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
686 pim_ifp = ifp->info;
687 if (!pim_ifp)
688 continue;
689
690 /* scan per-interface (S,G) state */
691 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
692
693 if (ch->upstream != up)
694 continue;
695
696 pim_ifchannel_update_assert_tracking_desired(ch);
697
698 } /* scan iface channel list */
699 } /* scan iflist */
700}