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