]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Add some helper functions.
[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
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "zebra/rib.h"
25
26#include "log.h"
27#include "zclient.h"
28#include "memory.h"
29#include "thread.h"
30#include "linklist.h"
dfe43e25
DW
31#include "vty.h"
32#include "plist.h"
0f588989
DS
33#include "hash.h"
34#include "jhash.h"
12e41d03
DL
35
36#include "pimd.h"
37#include "pim_pim.h"
38#include "pim_str.h"
39#include "pim_time.h"
40#include "pim_iface.h"
41#include "pim_join.h"
42#include "pim_zlookup.h"
43#include "pim_upstream.h"
44#include "pim_ifchannel.h"
45#include "pim_neighbor.h"
46#include "pim_rpf.h"
47#include "pim_zebra.h"
48#include "pim_oil.h"
49#include "pim_macro.h"
8f5f5e91 50#include "pim_rp.h"
f14248dd 51#include "pim_br.h"
627ed2a3 52#include "pim_register.h"
12e41d03 53
0f588989
DS
54struct hash *pim_upstream_hash = NULL;
55struct list *pim_upstream_list = NULL;
56
12e41d03
DL
57static void join_timer_start(struct pim_upstream *up);
58static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
59
cfa91a87
DS
60/*
61 * A (*,G) or a (*,*) is going away
62 * remove the parent pointer from
63 * those pointing at us
64 */
65static void
66pim_upstream_remove_children (struct pim_upstream *up)
67{
cfa91a87
DS
68 struct pim_upstream *child;
69
03417ccd 70 if (!up->sources)
cfa91a87
DS
71 return;
72
03417ccd 73 while (!list_isempty (up->sources))
cfa91a87 74 {
03417ccd
DS
75 child = listnode_head (up->sources);
76 child->parent = NULL;
77 listnode_delete (up->sources, child);
cfa91a87
DS
78 }
79}
80
81/*
82 * A (*,G) or a (*,*) is being created
83 * Find the children that would point
84 * at us.
85 */
86static void
87pim_upstream_find_new_children (struct pim_upstream *up)
88{
89 struct pim_upstream *child;
90 struct listnode *ch_node;
91
4ed0af70
DS
92 if ((up->sg.src.s_addr != INADDR_ANY) &&
93 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
94 return;
95
4ed0af70
DS
96 if ((up->sg.src.s_addr == INADDR_ANY) &&
97 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
98 return;
99
0f588989 100 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child))
cfa91a87 101 {
4ed0af70 102 if ((up->sg.grp.s_addr != INADDR_ANY) &&
0f588989 103 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
cfa91a87 104 (child != up))
03417ccd
DS
105 {
106 child->parent = up;
107 listnode_add_sort (up->sources, child);
108 }
cfa91a87
DS
109 }
110}
111
4d99418b
DS
112/*
113 * If we have a (*,*) || (S,*) there is no parent
114 * If we have a (S,G), find the (*,G)
115 * If we have a (*,G), find the (*,*)
116 */
117static struct pim_upstream *
03417ccd 118pim_upstream_find_parent (struct pim_upstream *child)
4d99418b 119{
03417ccd
DS
120 struct prefix_sg any = child->sg;
121 struct pim_upstream *up = NULL;
4d99418b
DS
122
123 // (S,G)
03417ccd
DS
124 if ((child->sg.src.s_addr != INADDR_ANY) &&
125 (child->sg.grp.s_addr != INADDR_ANY))
4d99418b 126 {
4ed0af70 127 any.src.s_addr = INADDR_ANY;
03417ccd
DS
128 up = pim_upstream_find (&any);
129
130 if (up)
131 listnode_add (up->sources, child);
132
133 return up;
4d99418b
DS
134 }
135
03417ccd 136 return NULL;
4d99418b
DS
137}
138
12e41d03
DL
139void pim_upstream_free(struct pim_upstream *up)
140{
141 XFREE(MTYPE_PIM_UPSTREAM, up);
142}
143
144static void upstream_channel_oil_detach(struct pim_upstream *up)
145{
146 if (up->channel_oil) {
147 pim_channel_oil_del(up->channel_oil);
25a335e0 148 up->channel_oil = NULL;
12e41d03
DL
149 }
150}
151
e5905a3b
DS
152void
153pim_upstream_del(struct pim_upstream *up, const char *name)
12e41d03 154{
e5905a3b
DS
155 if (PIM_DEBUG_PIM_TRACE)
156 {
157 zlog_debug ("%s: Delete (%s) ref count: %d",
158 name, pim_str_sg_dump (&up->sg), up->ref_count);
159 }
160 --up->ref_count;
161
162 if (up->ref_count >= 1)
163 return;
164
594a78cc
DS
165 if (PIM_DEBUG_PIM_TRACE)
166 zlog_debug ("%s: %s is being deleted",
167 __PRETTY_FUNCTION__,
168 pim_str_sg_dump (&up->sg));
12e41d03 169 THREAD_OFF(up->t_join_timer);
f14248dd 170 THREAD_OFF(up->t_ka_timer);
792f4d29 171 THREAD_OFF(up->t_rs_timer);
12e41d03 172
cfa91a87 173 pim_upstream_remove_children (up);
7fe1f662 174 pim_mroute_del (up->channel_oil);
12e41d03
DL
175 upstream_channel_oil_detach(up);
176
03417ccd
DS
177 if (up->sources)
178 list_delete (up->sources);
179 up->sources = NULL;
180
12e41d03
DL
181 /*
182 notice that listnode_delete() can't be moved
183 into pim_upstream_free() because the later is
184 called by list_delete_all_node()
185 */
03417ccd
DS
186 if (up->parent)
187 {
188 listnode_delete (up->parent->sources, up);
189 up->parent = NULL;
190 }
0f588989
DS
191 listnode_delete (pim_upstream_list, up);
192 hash_release (pim_upstream_hash, up);
12e41d03
DL
193
194 pim_upstream_free(up);
195}
196
56638739
DS
197void
198pim_upstream_send_join (struct pim_upstream *up)
12e41d03 199{
12e41d03 200 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 201 char rpf_str[PREFIX_STRLEN];
63c59d0c 202 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 203 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
c9802954 204 pim_str_sg_dump (&up->sg), rpf_str, pim_upstream_state2str (up->join_state),
56638739 205 up->rpf.source_nexthop.interface->name);
63c59d0c 206 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
05e451f8 207 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
56638739 208 __PRETTY_FUNCTION__,
05e451f8 209 pim_str_sg_dump (&up->sg), rpf_str);
12e41d03
DL
210 /* warning only */
211 }
212 }
56638739 213
12e41d03
DL
214 /* send Join(S,G) to the current upstream neighbor */
215 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 216 up->rpf.rpf_addr.u.prefix4,
372eab92 217 up,
12e41d03
DL
218 1 /* join */);
219}
220
221static int on_join_timer(struct thread *t)
222{
223 struct pim_upstream *up;
224
225 zassert(t);
226 up = THREAD_ARG(t);
227 zassert(up);
228
bb6e291f
DS
229 up->t_join_timer = NULL;
230
231 /*
232 * In the case of a HFR we will not ahve anyone to send this to.
233 */
0bf27c5c 234 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
bb6e291f
DS
235 return 0;
236
eb345962
DS
237 /*
238 * Don't send the join if the outgoing interface is a loopback
239 * But since this might change leave the join timer running
240 */
241 if (!if_is_loopback (up->rpf.source_nexthop.interface))
242 pim_upstream_send_join (up);
12e41d03 243
12e41d03
DL
244 join_timer_start(up);
245
246 return 0;
247}
248
249static void join_timer_start(struct pim_upstream *up)
250{
251 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 252 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
12e41d03
DL
253 __PRETTY_FUNCTION__,
254 qpim_t_periodic,
05e451f8 255 pim_str_sg_dump (&up->sg));
12e41d03
DL
256 }
257
8e38a2cf 258 THREAD_OFF (up->t_join_timer);
12e41d03
DL
259 THREAD_TIMER_ON(master, up->t_join_timer,
260 on_join_timer,
261 up, qpim_t_periodic);
262}
263
264void pim_upstream_join_timer_restart(struct pim_upstream *up)
265{
266 THREAD_OFF(up->t_join_timer);
267 join_timer_start(up);
268}
269
270static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
271 int interval_msec)
272{
273 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 274 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
12e41d03
DL
275 __PRETTY_FUNCTION__,
276 interval_msec,
05e451f8 277 pim_str_sg_dump (&up->sg));
12e41d03
DL
278 }
279
280 THREAD_OFF(up->t_join_timer);
281 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
282 on_join_timer,
283 up, interval_msec);
284}
285
286void pim_upstream_join_suppress(struct pim_upstream *up,
287 struct in_addr rpf_addr,
288 int holdtime)
289{
290 long t_joinsuppress_msec;
291 long join_timer_remain_msec;
292
293 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
294 1000 * holdtime);
295
296 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
297
298 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 299 char rpf_str[INET_ADDRSTRLEN];
12e41d03 300 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 301 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
12e41d03 302 __FILE__, __PRETTY_FUNCTION__,
05e451f8 303 pim_str_sg_dump (&up->sg),
12e41d03
DL
304 rpf_str,
305 join_timer_remain_msec, t_joinsuppress_msec);
306 }
307
308 if (join_timer_remain_msec < t_joinsuppress_msec) {
309 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 310 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
12e41d03 311 __FILE__, __PRETTY_FUNCTION__,
05e451f8 312 pim_str_sg_dump (&up->sg), t_joinsuppress_msec);
12e41d03
DL
313 }
314
315 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
316 }
317}
318
319void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
320 struct pim_upstream *up,
321 struct in_addr rpf_addr)
322{
323 long join_timer_remain_msec;
324 int t_override_msec;
325
326 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
327 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
328
329 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 330 char rpf_str[INET_ADDRSTRLEN];
12e41d03 331 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 332 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
12e41d03 333 debug_label,
05e451f8 334 pim_str_sg_dump (&up->sg), rpf_str,
12e41d03
DL
335 join_timer_remain_msec, t_override_msec);
336 }
337
338 if (join_timer_remain_msec > t_override_msec) {
339 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 340 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
12e41d03 341 debug_label,
05e451f8 342 pim_str_sg_dump (&up->sg),
12e41d03
DL
343 t_override_msec);
344 }
345
346 pim_upstream_join_timer_restart_msec(up, t_override_msec);
347 }
348}
349
350static void forward_on(struct pim_upstream *up)
351{
352 struct listnode *ifnode;
353 struct listnode *ifnextnode;
354 struct listnode *chnode;
355 struct listnode *chnextnode;
356 struct interface *ifp;
357 struct pim_interface *pim_ifp;
358 struct pim_ifchannel *ch;
359
360 /* scan all interfaces */
469351b3 361 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
362 pim_ifp = ifp->info;
363 if (!pim_ifp)
364 continue;
365
366 /* scan per-interface (S,G) state */
367 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
368
369 if (ch->upstream != up)
370 continue;
371
372 if (pim_macro_chisin_oiflist(ch))
373 pim_forward_start(ch);
374
375 } /* scan iface channel list */
376 } /* scan iflist */
377}
378
379static void forward_off(struct pim_upstream *up)
380{
381 struct listnode *ifnode;
382 struct listnode *ifnextnode;
383 struct listnode *chnode;
384 struct listnode *chnextnode;
385 struct interface *ifp;
386 struct pim_interface *pim_ifp;
387 struct pim_ifchannel *ch;
388
389 /* scan all interfaces */
469351b3 390 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
391 pim_ifp = ifp->info;
392 if (!pim_ifp)
393 continue;
394
395 /* scan per-interface (S,G) state */
396 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
397
398 if (ch->upstream != up)
399 continue;
400
401 pim_forward_stop(ch);
402
403 } /* scan iface channel list */
404 } /* scan iflist */
405}
406
bb6e291f
DS
407static int
408pim_upstream_could_register (struct pim_upstream *up)
409{
410 struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
411
35917570 412 if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
bb6e291f
DS
413 pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
414 return 1;
415
416 return 0;
417}
418
7fcdfb34
DS
419void
420pim_upstream_switch(struct pim_upstream *up,
421 enum pim_upstream_state new_state)
12e41d03
DL
422{
423 enum pim_upstream_state old_state = up->join_state;
424
12e41d03 425 if (PIM_DEBUG_PIM_EVENTS) {
c9802954 426 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
12e41d03 427 __PRETTY_FUNCTION__,
c9802954
DS
428 pim_str_sg_dump (&up->sg),
429 pim_upstream_state2str (up->join_state),
430 pim_upstream_state2str (new_state));
12e41d03
DL
431 }
432
bb027ee8
DS
433 /*
434 * This code still needs work.
435 */
436 switch (up->join_state)
437 {
438 case PIM_UPSTREAM_PRUNE:
0bf27c5c 439 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
7747bad6
DS
440 {
441 up->join_state = new_state;
442 up->state_transition = pim_time_monotonic_sec ();
443 }
444 break;
bb027ee8
DS
445 case PIM_UPSTREAM_JOIN_PENDING:
446 break;
447 case PIM_UPSTREAM_NOTJOINED:
448 case PIM_UPSTREAM_JOINED:
449 up->join_state = new_state;
450 up->state_transition = pim_time_monotonic_sec();
451
452 break;
453 }
454
12e41d03
DL
455 pim_upstream_update_assert_tracking_desired(up);
456
457 if (new_state == PIM_UPSTREAM_JOINED) {
81900c5a
DS
458 if (old_state != PIM_UPSTREAM_JOINED)
459 {
0bf27c5c 460 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
81900c5a 461 forward_on(up);
0bf27c5c 462 if (pim_upstream_could_register (up))
bb6e291f 463 {
0bf27c5c 464 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
a9b59879 465 if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
bb6e291f
DS
466 {
467 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
468 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
469 }
470 }
471 else
472 {
473 pim_upstream_send_join (up);
474 join_timer_start (up);
475 }
81900c5a
DS
476 }
477 else
478 {
479 forward_on (up);
480 }
12e41d03
DL
481 }
482 else {
483 forward_off(up);
484 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 485 up->rpf.rpf_addr.u.prefix4,
372eab92 486 up,
12e41d03 487 0 /* prune */);
7fcdfb34
DS
488 if (up->t_join_timer)
489 THREAD_OFF(up->t_join_timer);
12e41d03 490 }
12e41d03
DL
491}
492
03417ccd
DS
493static int
494pim_upstream_compare (void *arg1, void *arg2)
495{
496 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
497 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
498
499 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
500 return -1;
501
502 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
503 return 1;
504
505 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
506 return -1;
507
508 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
509 return 1;
510
511 return 0;
512}
513
4ed0af70 514static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
4a40c37a
DS
515 struct interface *incoming,
516 int flags)
12e41d03
DL
517{
518 struct pim_upstream *up;
2f702571 519 enum pim_rpf_result rpf_result;
12e41d03 520
36d9e7dc 521 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
12e41d03 522 if (!up) {
36d9e7dc 523 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 524 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 525 return NULL;
12e41d03
DL
526 }
527
5074a423 528 up->sg = *sg;
0f588989 529 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
36d6bd7d 530 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
8f5f5e91
DS
531 {
532 if (PIM_DEBUG_PIM_TRACE)
533 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
534
03417ccd 535 hash_release (pim_upstream_hash, up);
8f5f5e91
DS
536 XFREE (MTYPE_PIM_UPSTREAM, up);
537 return NULL;
538 }
539
03417ccd
DS
540 up->parent = pim_upstream_find_parent (up);
541 if (up->sg.src.s_addr == INADDR_ANY)
542 {
543 up->sources = list_new ();
544 up->sources->cmp = pim_upstream_compare;
545 }
546 else
547 up->sources = NULL;
548
cfa91a87 549 pim_upstream_find_new_children (up);
4a40c37a 550 up->flags = flags;
12e41d03 551 up->ref_count = 1;
4a4c4a07
DS
552 up->t_join_timer = NULL;
553 up->t_ka_timer = NULL;
792f4d29 554 up->t_rs_timer = NULL;
12e41d03
DL
555 up->join_state = 0;
556 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 557 up->channel_oil = NULL;
f9e0ab5b 558 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03 559
f24405b1 560 up->rpf.source_nexthop.interface = NULL;
63c59d0c
DS
561 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
562 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
563 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
564 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
565 up->rpf.rpf_addr.family = AF_INET;
566 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 567
d3dd1804 568 rpf_result = pim_rpf_update(up, NULL);
2f702571 569 if (rpf_result == PIM_RPF_FAILURE) {
4a40c37a
DS
570 if (PIM_DEBUG_PIM_TRACE)
571 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
572 pim_str_sg_dump (&up->sg));
03417ccd
DS
573
574 if (up->parent)
575 {
576 listnode_delete (up->parent->sources, up);
577 up->parent = NULL;
578 }
579 pim_upstream_remove_children (up);
580 if (up->sources)
581 list_delete (up->sources);
582
583 hash_release (pim_upstream_hash, up);
2f702571
DS
584 XFREE(MTYPE_PIM_UPSTREAM, up);
585 return NULL;
586 }
12e41d03 587
0f588989 588 listnode_add_sort(pim_upstream_list, up);
12e41d03 589
03417ccd
DS
590 if (PIM_DEBUG_PIM_TRACE)
591 zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg));
592
12e41d03
DL
593 return up;
594}
595
4ed0af70 596struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03 597{
0f588989
DS
598 struct pim_upstream lookup;
599 struct pim_upstream *up = NULL;
12e41d03 600
0f588989
DS
601 lookup.sg = *sg;
602 up = hash_lookup (pim_upstream_hash, &lookup);
603 return up;
12e41d03
DL
604}
605
4ed0af70 606struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
4a40c37a 607 struct interface *incoming,
e5905a3b 608 int flags, const char *name)
12e41d03 609{
594a78cc 610 struct pim_upstream *up = NULL;
e5905a3b 611 int found = 0;
5074a423 612 up = pim_upstream_find(sg);
12e41d03
DL
613 if (up) {
614 ++up->ref_count;
16b72591 615 up->flags |= flags;
e5905a3b 616 found = 1;
12e41d03
DL
617 }
618 else {
4a40c37a 619 up = pim_upstream_new(sg, incoming, flags);
12e41d03
DL
620 }
621
e5905a3b 622 if (PIM_DEBUG_TRACE)
f4075cb4
DS
623 {
624 if (up)
625 zlog_debug("%s(%s): (%s), found: %d: ref_count: %d",
626 __PRETTY_FUNCTION__, name,
627 pim_str_sg_dump (&up->sg), found,
628 up->ref_count);
629 else
630 zlog_debug("%s(%s): (%s) failure to create",
631 __PRETTY_FUNCTION__, name,
632 pim_str_sg_dump (sg));
633 }
12e41d03 634
e5905a3b 635 return up;
12e41d03
DL
636}
637
7a3ddda5
DS
638static int
639pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
640 struct pim_ifchannel *ch)
641{
642 struct pim_upstream *parent = up->parent;
643
644 if (ch->upstream == up)
645 {
646 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
647 return 1;
648 }
649 /*
650 * joins (*,G)
651 */
652 if (parent && ch->upstream == parent)
653 {
654 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
655 return 1;
656 }
657
658 return 0;
659}
660
12e41d03
DL
661/*
662 Evaluate JoinDesired(S,G):
663
664 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
665 in the set:
666
667 inherited_olist(S,G) =
668 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
669
670 JoinDesired(S,G) may be affected by changes in the following:
671
672 pim_ifp->primary_address
673 pim_ifp->pim_dr_addr
674 ch->ifassert_winner_metric
675 ch->ifassert_winner
676 ch->local_ifmembership
677 ch->ifjoin_state
678 ch->upstream->rpf.source_nexthop.mrib_metric_preference
679 ch->upstream->rpf.source_nexthop.mrib_route_metric
680 ch->upstream->rpf.source_nexthop.interface
681
682 See also pim_upstream_update_join_desired() below.
683 */
684int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
685{
686 struct listnode *ifnode;
687 struct listnode *ifnextnode;
688 struct listnode *chnode;
689 struct listnode *chnextnode;
690 struct interface *ifp;
691 struct pim_interface *pim_ifp;
692 struct pim_ifchannel *ch;
7a3ddda5 693 int ret = 0;
12e41d03
DL
694
695 /* scan all interfaces */
469351b3 696 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
697 pim_ifp = ifp->info;
698 if (!pim_ifp)
699 continue;
700
701 /* scan per-interface (S,G) state */
7a3ddda5
DS
702 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
703 {
704 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
705 } /* scan iface channel list */
12e41d03
DL
706 } /* scan iflist */
707
7a3ddda5 708 return ret; /* false */
12e41d03
DL
709}
710
711/*
712 See also pim_upstream_evaluate_join_desired() above.
713*/
714void pim_upstream_update_join_desired(struct pim_upstream *up)
715{
716 int was_join_desired; /* boolean */
717 int is_join_desired; /* boolean */
718
719 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
720
721 is_join_desired = pim_upstream_evaluate_join_desired(up);
722 if (is_join_desired)
723 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
724 else
725 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
726
727 /* switched from false to true */
728 if (is_join_desired && !was_join_desired) {
12e41d03
DL
729 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
730 return;
731 }
732
733 /* switched from true to false */
734 if (!is_join_desired && was_join_desired) {
12e41d03
DL
735 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
736 return;
737 }
738}
739
740/*
741 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
742 Transitions from Joined State
743 RPF'(S,G) GenID changes
744
745 The upstream (S,G) state machine remains in Joined state. If the
746 Join Timer is set to expire in more than t_override seconds, reset
747 it so that it expires after t_override seconds.
748*/
749void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
750{
751 struct listnode *up_node;
752 struct listnode *up_nextnode;
753 struct pim_upstream *up;
754
755 /*
0f588989
DS
756 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
757 */
758 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03
DL
759
760 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
761 char neigh_str[INET_ADDRSTRLEN];
762 char rpf_addr_str[PREFIX_STRLEN];
12e41d03 763 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
63c59d0c 764 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 765 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 766 __PRETTY_FUNCTION__,
05e451f8 767 neigh_str, pim_str_sg_dump (&up->sg),
12e41d03
DL
768 up->join_state == PIM_UPSTREAM_JOINED,
769 rpf_addr_str);
770 }
771
772 /* consider only (S,G) upstream in Joined state */
773 if (up->join_state != PIM_UPSTREAM_JOINED)
774 continue;
775
776 /* match RPF'(S,G)=neigh_addr */
63c59d0c 777 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
12e41d03
DL
778 continue;
779
780 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
781 up, neigh_addr);
782 }
783}
784
785
786void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
787 struct interface *old_rpf_ifp)
788{
789 struct listnode *ifnode;
790 struct listnode *ifnextnode;
791 struct interface *ifp;
792
793 /* scan all interfaces */
469351b3 794 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
795 struct listnode *chnode;
796 struct listnode *chnextnode;
797 struct pim_ifchannel *ch;
798 struct pim_interface *pim_ifp;
799
800 pim_ifp = ifp->info;
801 if (!pim_ifp)
802 continue;
803
804 /* search all ifchannels */
805 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
806 if (ch->upstream != up)
807 continue;
808
809 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
810 if (
811 /* RPF_interface(S) was NOT I */
812 (old_rpf_ifp == ch->interface)
813 &&
814 /* RPF_interface(S) stopped being I */
815 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
816 ) {
817 assert_action_a5(ch);
818 }
819 } /* PIM_IFASSERT_I_AM_LOSER */
820
821 pim_ifchannel_update_assert_tracking_desired(ch);
822 }
823 }
824}
825
826void pim_upstream_update_could_assert(struct pim_upstream *up)
827{
828 struct listnode *ifnode;
829 struct listnode *ifnextnode;
830 struct listnode *chnode;
831 struct listnode *chnextnode;
832 struct interface *ifp;
833 struct pim_interface *pim_ifp;
834 struct pim_ifchannel *ch;
835
836 /* scan all interfaces */
469351b3 837 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
838 pim_ifp = ifp->info;
839 if (!pim_ifp)
840 continue;
841
842 /* scan per-interface (S,G) state */
843 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
844
845 if (ch->upstream != up)
846 continue;
847
848 pim_ifchannel_update_could_assert(ch);
849
850 } /* scan iface channel list */
851 } /* scan iflist */
852}
853
854void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
855{
856 struct listnode *ifnode;
857 struct listnode *ifnextnode;
858 struct listnode *chnode;
859 struct listnode *chnextnode;
860 struct interface *ifp;
861 struct pim_interface *pim_ifp;
862 struct pim_ifchannel *ch;
863
864 /* scan all interfaces */
469351b3 865 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
866 pim_ifp = ifp->info;
867 if (!pim_ifp)
868 continue;
869
870 /* scan per-interface (S,G) state */
871 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
872
873 if (ch->upstream != up)
874 continue;
875
876 pim_ifchannel_update_my_assert_metric(ch);
877
878 } /* scan iface channel list */
879 } /* scan iflist */
880}
881
882static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
883{
884 struct listnode *ifnode;
885 struct listnode *ifnextnode;
886 struct listnode *chnode;
887 struct listnode *chnextnode;
888 struct interface *ifp;
889 struct pim_interface *pim_ifp;
890 struct pim_ifchannel *ch;
891
892 /* scan all interfaces */
469351b3 893 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
894 pim_ifp = ifp->info;
895 if (!pim_ifp)
896 continue;
897
898 /* scan per-interface (S,G) state */
899 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
900
901 if (ch->upstream != up)
902 continue;
903
904 pim_ifchannel_update_assert_tracking_desired(ch);
905
906 } /* scan iface channel list */
907 } /* scan iflist */
908}
f14248dd
DS
909
910/*
911 * On an RP, the PMBR value must be cleared when the
912 * Keepalive Timer expires
913 */
914static int
915pim_upstream_keep_alive_timer (struct thread *t)
916{
917 struct pim_upstream *up;
918
919 up = THREAD_ARG(t);
920
4ed0af70 921 if (I_am_RP (up->sg.grp))
25a335e0 922 {
65e1fcd7 923 pim_br_clear_pmbr (&up->sg);
25a335e0
DS
924 /*
925 * We need to do more here :)
926 * But this is the start.
927 */
928 }
14315ea8
DS
929
930 pim_mroute_update_counters (up->channel_oil);
931
bebc7290
DS
932 if (PIM_DEBUG_MROUTE)
933 {
934 zlog_debug ("New: %llu %lu %lu %lu", up->channel_oil->cc.lastused, up->channel_oil->cc.pktcnt,
935 up->channel_oil->cc.bytecnt, up->channel_oil->cc.wrong_if);
936 zlog_debug ("old: %llu %lu %lu %lu", up->channel_oil->cc.lastused, up->channel_oil->cc.oldpktcnt,
937 up->channel_oil->cc.oldbytecnt, up->channel_oil->cc.oldwrong_if);
938 }
e3be0432 939 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
5f0336ed 940 (up->channel_oil->cc.lastused/100 >= qpim_keep_alive_time))
14315ea8
DS
941 {
942 pim_mroute_del (up->channel_oil);
d854589a
DS
943 THREAD_OFF (up->t_ka_timer);
944 THREAD_OFF (up->t_rs_timer);
945 THREAD_OFF (up->t_join_timer);
63c59d0c 946 pim_joinprune_send (up->rpf.source_nexthop.interface, up->rpf.rpf_addr.u.prefix4,
372eab92 947 up, 0);
a9b59879 948 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM (up->flags);
5ce79466 949 if (PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(up->flags))
e5905a3b
DS
950 {
951 PIM_UPSTREAM_FLAG_UNSET_CREATED_BY_UPSTREAM(up->flags);
952 pim_upstream_del (up, __PRETTY_FUNCTION__);
953 }
14315ea8 954 }
25a335e0
DS
955 else
956 {
14315ea8 957 up->t_ka_timer = NULL;
4304f95c 958 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
25a335e0 959 }
14315ea8 960
cb40b272 961 return 1;
f14248dd
DS
962}
963
f14248dd
DS
964void
965pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
966 uint32_t time)
967{
00d2f9e4 968 THREAD_OFF (up->t_ka_timer);
f14248dd
DS
969 THREAD_TIMER_ON (master,
970 up->t_ka_timer,
971 pim_upstream_keep_alive_timer,
972 up, time);
973}
cb40b272
DS
974
975/*
976 * 4.2.1 Last-Hop Switchover to the SPT
977 *
978 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
979 * RP. Once traffic from sources to joined groups arrives at a last-hop
980 * router, it has the option of switching to receive the traffic on a
981 * shortest path tree (SPT).
982 *
983 * The decision for a router to switch to the SPT is controlled as
984 * follows:
985 *
986 * void
987 * CheckSwitchToSpt(S,G) {
988 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
989 * (+) pim_include(S,G) != NULL )
990 * AND SwitchToSptDesired(S,G) ) {
991 * # Note: Restarting the KAT will result in the SPT switch
992 * set KeepaliveTimer(S,G) to Keepalive_Period
993 * }
994 * }
995 *
996 * SwitchToSptDesired(S,G) is a policy function that is implementation
997 * defined. An "infinite threshold" policy can be implemented by making
998 * SwitchToSptDesired(S,G) return false all the time. A "switch on
999 * first packet" policy can be implemented by making
1000 * SwitchToSptDesired(S,G) return true once a single packet has been
1001 * received for the source and group.
1002 */
1003int
4ed0af70 1004pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 1005{
4ed0af70 1006 if (I_am_RP (sg->grp))
a3b58b4a
DS
1007 return 1;
1008
cb40b272
DS
1009 return 0;
1010}
d7259eac 1011
80d9c3a0
DS
1012int
1013pim_upstream_is_sg_rpt (struct pim_upstream *up)
1014{
1015 // FIXME: When we implement the ability to
1016 // receive a s,g,rpt prune this can be modified
1017 return 0;
1018}
1019
d7259eac 1020const char *
c9802954 1021pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 1022{
c9802954 1023 switch (join_state)
d7259eac
DS
1024 {
1025 case PIM_UPSTREAM_NOTJOINED:
e775c0a4 1026 return "NotJoined";
d7259eac
DS
1027 break;
1028 case PIM_UPSTREAM_JOINED:
e775c0a4 1029 return "Joined";
d7259eac
DS
1030 break;
1031 case PIM_UPSTREAM_JOIN_PENDING:
e775c0a4 1032 return "JoinPending";
d7259eac
DS
1033 break;
1034 case PIM_UPSTREAM_PRUNE:
1035 return "Prune";
1036 break;
1037 }
e775c0a4 1038 return "Unknown";
d7259eac 1039}
627ed2a3
DS
1040
1041static int
1042pim_upstream_register_stop_timer (struct thread *t)
1043{
4df01a4e 1044 struct pim_interface *pim_ifp;
627ed2a3
DS
1045 struct pim_upstream *up;
1046 struct pim_rpf *rpg;
1047 struct ip ip_hdr;
627ed2a3
DS
1048 up = THREAD_ARG (t);
1049
79ce47c0 1050 THREAD_TIMER_OFF (up->t_rs_timer);
627ed2a3
DS
1051 up->t_rs_timer = NULL;
1052
1053 if (PIM_DEBUG_TRACE)
1054 {
d5ed8a9c
DS
1055 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
1056 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg),
c9802954 1057 pim_upstream_state2str(up->join_state));
627ed2a3
DS
1058 }
1059
1060 switch (up->join_state)
1061 {
1062 case PIM_UPSTREAM_JOIN_PENDING:
1063 up->join_state = PIM_UPSTREAM_JOINED;
bb027ee8
DS
1064 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1065 break;
1066 case PIM_UPSTREAM_JOINED:
627ed2a3
DS
1067 break;
1068 case PIM_UPSTREAM_PRUNE:
4df01a4e 1069 pim_ifp = up->rpf.source_nexthop.interface->info;
7ef66046
DS
1070 if (!pim_ifp)
1071 {
1072 if (PIM_DEBUG_TRACE)
1073 zlog_debug ("%s: Interface: %s is not configured for pim",
1074 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1075 return 0;
1076 }
627ed2a3
DS
1077 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
1078 pim_upstream_start_register_stop_timer (up, 1);
1079
4ed0af70 1080 rpg = RP (up->sg.grp);
627ed2a3
DS
1081 memset (&ip_hdr, 0, sizeof (struct ip));
1082 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1083 ip_hdr.ip_hl = 5;
1084 ip_hdr.ip_v = 4;
4ed0af70
DS
1085 ip_hdr.ip_src = up->sg.src;
1086 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1087 ip_hdr.ip_len = htons (20);
627ed2a3 1088 // checksum is broken
4df01a4e
DS
1089 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
1090 pim_ifp->primary_address, rpg, 1);
627ed2a3
DS
1091 break;
1092 default:
1093 break;
1094 }
1095
1096 return 0;
1097}
1098
1099void
1100pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1101{
1102 uint32_t time;
1103
1104 if (up->t_rs_timer)
1105 {
1106 THREAD_TIMER_OFF (up->t_rs_timer);
1107 up->t_rs_timer = NULL;
1108 }
1109
1110 if (!null_register)
1111 {
1112 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1113 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1114 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1115 }
1116 else
1117 time = PIM_REGISTER_PROBE_PERIOD;
1118
1119 if (PIM_DEBUG_TRACE)
1120 {
05e451f8
DS
1121 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1122 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), time);
627ed2a3
DS
1123 }
1124 THREAD_TIMER_ON (master, up->t_rs_timer,
1125 pim_upstream_register_stop_timer,
1126 up, time);
1127}
4fdc8f36
DS
1128
1129/*
1130 * For a given upstream, determine the inherited_olist
1131 * and apply it.
219e0013
DS
1132 *
1133 * inherited_olist(S,G,rpt) =
1134 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1135 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1136 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1137 *
1138 * inherited_olist(S,G) =
1139 * inherited_olist(S,G,rpt) (+)
1140 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1141 *
4fdc8f36
DS
1142 * return 1 if there are any output interfaces
1143 * return 0 if there are not any output interfaces
1144 */
1145int
1146pim_upstream_inherited_olist (struct pim_upstream *up)
1147{
219e0013
DS
1148 struct pim_interface *pim_ifp;
1149 struct listnode *ifnextnode;
1150 struct listnode *chnextnode;
1151 struct pim_ifchannel *ch;
1152 struct listnode *chnode;
1153 struct listnode *ifnode;
1154 struct interface *ifp;
219e0013
DS
1155 int output_intf = 0;
1156
3667b0bc 1157 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1158 if (pim_ifp && !up->channel_oil)
3667b0bc 1159 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1160
7a3ddda5 1161 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
219e0013 1162 {
7a3ddda5
DS
1163 pim_ifp = ifp->info;
1164 if (!pim_ifp)
1165 continue;
219e0013 1166
7a3ddda5
DS
1167 for (ALL_LIST_ELEMENTS (pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
1168 {
1169 if (pim_upstream_evaluate_join_desired_interface (up, ch))
219e0013 1170 {
7a3ddda5
DS
1171 pim_channel_add_oif (up->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
1172 output_intf++;
219e0013
DS
1173 }
1174 }
1175 }
1176
483eef9d
DS
1177 /*
1178 * If we have output_intf switch state to Join and work like normal
1179 * If we don't have an output_intf that means we are probably a
1180 * switch on a stick so turn on forwarding to just accept the
1181 * incoming packets so we don't bother the other stuff!
1182 */
1183 if (output_intf)
1184 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1185 else
1186 forward_on (up);
219e0013
DS
1187
1188 return output_intf;
4fdc8f36 1189}
d3dd1804 1190
80d9c3a0
DS
1191int
1192pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1193{
1194 // FIXME: Currently this is not implemented
1195 return 0;
1196}
1197
d3dd1804
DS
1198/*
1199 * When we have a new neighbor,
1200 * find upstreams that don't have their rpf_addr
1201 * set and see if the new neighbor allows
1202 * the join to be sent
1203 */
1204void
1205pim_upstream_find_new_rpf (void)
1206{
1207 struct listnode *up_node;
1208 struct listnode *up_nextnode;
1209 struct pim_upstream *up;
1210
1211 /*
0f588989
DS
1212 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1213 */
1214 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1215 {
63c59d0c 1216 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804
DS
1217 {
1218 if (PIM_DEBUG_PIM_TRACE)
1219 zlog_debug ("Upstream %s without a path to send join, checking",
1220 pim_str_sg_dump (&up->sg));
1221 pim_rpf_update (up, NULL);
1222 }
1223 }
1224}
0f588989 1225
0f588989
DS
1226static unsigned int
1227pim_upstream_hash_key (void *arg)
1228{
1229 struct pim_upstream *up = (struct pim_upstream *)arg;
1230
1231 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1232}
1233
1234void pim_upstream_terminate (void)
1235{
1236 if (pim_upstream_list)
1237 list_free (pim_upstream_list);
1238 pim_upstream_list = NULL;
1239
1240 if (pim_upstream_hash)
1241 hash_free (pim_upstream_hash);
1242}
1243
1244static int
1245pim_upstream_equal (const void *arg1, const void *arg2)
1246{
1247 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1248 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1249
1250 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1251 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1252 return 1;
1253
1254 return 0;
1255}
1256
040d86ad
DS
1257void
1258pim_upstream_init (void)
0f588989
DS
1259{
1260 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1261 pim_upstream_equal);
1262
1263 pim_upstream_list = list_new ();
1264 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1265 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1266
1267}