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