]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
lib: Fix 'show thread cpu' to display active threads
[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{
e43b8697
DS
994 if (up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
995 return 1;
996
80d9c3a0
DS
997 return 0;
998}
3a66b17b
DS
999/*
1000 * After receiving a packet set SPTbit:
1001 * void
1002 * Update_SPTbit(S,G,iif) {
1003 * if ( iif == RPF_interface(S)
1004 * AND JoinDesired(S,G) == TRUE
1005 * AND ( DirectlyConnected(S) == TRUE
1006 * OR RPF_interface(S) != RPF_interface(RP(G))
1007 * OR inherited_olist(S,G,rpt) == NULL
1008 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1009 * ( RPF'(S,G) != NULL ) )
1010 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1011 * Set SPTbit(S,G) to TRUE
1012 * }
1013 * }
1014 */
1015void
1016pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
1017{
1018 struct pim_rpf *grpf = NULL;
1019
1020 // iif == RPF_interfvace(S)
1021 if (up->rpf.source_nexthop.interface != incoming)
1022 {
1023 if (PIM_DEBUG_TRACE)
1024 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1025 __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
1026 return;
1027 }
1028
1029 // AND JoinDesired(S,G) == TRUE
1030 // FIXME
1031
1032 // DirectlyConnected(S) == TRUE
1033 if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
1034 {
1035 if (PIM_DEBUG_TRACE)
1036 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
1037 pim_str_sg_dump (&up->sg));
1038 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1039 return;
1040 }
1041
1042 // OR RPF_interface(S) != RPF_interface(RP(G))
1043 grpf = RP(up->sg.grp);
1044 if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
1045 {
1046 if (PIM_DEBUG_TRACE)
1047 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1048 __PRETTY_FUNCTION__, pim_str_sg_dump(&up->sg));
1049 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1050 return;
1051 }
1052
1053 // OR inherited_olist(S,G,rpt) == NULL
1054 if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
1055 {
1056 if (PIM_DEBUG_TRACE)
1057 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
1058 pim_str_sg_dump (&up->sg));
1059 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1060 return;
1061 }
1062
1063 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1064 // ( RPF'(S,G) != NULL ) )
1065 if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
1066 {
1067 if (PIM_DEBUG_TRACE)
1068 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
1069 pim_str_sg_dump (&up->sg));
1070 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1071 return;
1072 }
1073
1074 return;
1075}
80d9c3a0 1076
d7259eac 1077const char *
c9802954 1078pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 1079{
c9802954 1080 switch (join_state)
d7259eac
DS
1081 {
1082 case PIM_UPSTREAM_NOTJOINED:
e775c0a4 1083 return "NotJoined";
d7259eac
DS
1084 break;
1085 case PIM_UPSTREAM_JOINED:
e775c0a4 1086 return "Joined";
d7259eac
DS
1087 break;
1088 case PIM_UPSTREAM_JOIN_PENDING:
e775c0a4 1089 return "JoinPending";
d7259eac
DS
1090 break;
1091 case PIM_UPSTREAM_PRUNE:
1092 return "Prune";
1093 break;
1094 }
e775c0a4 1095 return "Unknown";
d7259eac 1096}
627ed2a3
DS
1097
1098static int
1099pim_upstream_register_stop_timer (struct thread *t)
1100{
4df01a4e 1101 struct pim_interface *pim_ifp;
627ed2a3
DS
1102 struct pim_upstream *up;
1103 struct pim_rpf *rpg;
1104 struct ip ip_hdr;
627ed2a3
DS
1105 up = THREAD_ARG (t);
1106
79ce47c0 1107 THREAD_TIMER_OFF (up->t_rs_timer);
627ed2a3
DS
1108 up->t_rs_timer = NULL;
1109
1110 if (PIM_DEBUG_TRACE)
1111 {
d5ed8a9c
DS
1112 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
1113 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg),
c9802954 1114 pim_upstream_state2str(up->join_state));
627ed2a3
DS
1115 }
1116
1117 switch (up->join_state)
1118 {
1119 case PIM_UPSTREAM_JOIN_PENDING:
1120 up->join_state = PIM_UPSTREAM_JOINED;
bb027ee8
DS
1121 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1122 break;
1123 case PIM_UPSTREAM_JOINED:
627ed2a3
DS
1124 break;
1125 case PIM_UPSTREAM_PRUNE:
4df01a4e 1126 pim_ifp = up->rpf.source_nexthop.interface->info;
7ef66046
DS
1127 if (!pim_ifp)
1128 {
1129 if (PIM_DEBUG_TRACE)
1130 zlog_debug ("%s: Interface: %s is not configured for pim",
1131 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1132 return 0;
1133 }
627ed2a3
DS
1134 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
1135 pim_upstream_start_register_stop_timer (up, 1);
1136
4ed0af70 1137 rpg = RP (up->sg.grp);
627ed2a3
DS
1138 memset (&ip_hdr, 0, sizeof (struct ip));
1139 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1140 ip_hdr.ip_hl = 5;
1141 ip_hdr.ip_v = 4;
4ed0af70
DS
1142 ip_hdr.ip_src = up->sg.src;
1143 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1144 ip_hdr.ip_len = htons (20);
627ed2a3 1145 // checksum is broken
4df01a4e
DS
1146 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
1147 pim_ifp->primary_address, rpg, 1);
627ed2a3
DS
1148 break;
1149 default:
1150 break;
1151 }
1152
1153 return 0;
1154}
1155
1156void
1157pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1158{
1159 uint32_t time;
1160
1161 if (up->t_rs_timer)
1162 {
1163 THREAD_TIMER_OFF (up->t_rs_timer);
1164 up->t_rs_timer = NULL;
1165 }
1166
1167 if (!null_register)
1168 {
1169 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1170 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1171 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1172 }
1173 else
1174 time = PIM_REGISTER_PROBE_PERIOD;
1175
1176 if (PIM_DEBUG_TRACE)
1177 {
05e451f8
DS
1178 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1179 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), time);
627ed2a3
DS
1180 }
1181 THREAD_TIMER_ON (master, up->t_rs_timer,
1182 pim_upstream_register_stop_timer,
1183 up, time);
1184}
4fdc8f36
DS
1185
1186/*
1187 * For a given upstream, determine the inherited_olist
1188 * and apply it.
219e0013
DS
1189 *
1190 * inherited_olist(S,G,rpt) =
1191 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1192 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1193 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1194 *
1195 * inherited_olist(S,G) =
1196 * inherited_olist(S,G,rpt) (+)
1197 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1198 *
4fdc8f36
DS
1199 * return 1 if there are any output interfaces
1200 * return 0 if there are not any output interfaces
1201 */
1202int
1203pim_upstream_inherited_olist (struct pim_upstream *up)
1204{
219e0013 1205 struct pim_interface *pim_ifp;
219e0013
DS
1206 struct listnode *chnextnode;
1207 struct pim_ifchannel *ch;
1208 struct listnode *chnode;
219e0013
DS
1209 int output_intf = 0;
1210
3667b0bc 1211 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1212 if (pim_ifp && !up->channel_oil)
3667b0bc 1213 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1214
ea4a71fc 1215 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
219e0013 1216 {
ea4a71fc 1217 pim_ifp = ch->interface->info;
7a3ddda5
DS
1218 if (!pim_ifp)
1219 continue;
219e0013 1220
ea4a71fc 1221 if (pim_upstream_evaluate_join_desired_interface (up, ch))
7a3ddda5 1222 {
ea4a71fc
DS
1223 pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
1224 output_intf++;
219e0013
DS
1225 }
1226 }
1227
483eef9d
DS
1228 /*
1229 * If we have output_intf switch state to Join and work like normal
1230 * If we don't have an output_intf that means we are probably a
1231 * switch on a stick so turn on forwarding to just accept the
1232 * incoming packets so we don't bother the other stuff!
1233 */
1234 if (output_intf)
1235 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1236 else
1237 forward_on (up);
219e0013
DS
1238
1239 return output_intf;
4fdc8f36 1240}
d3dd1804 1241
80d9c3a0
DS
1242int
1243pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1244{
ce0ddb4e 1245 return pim_channel_oil_empty (up->channel_oil);
80d9c3a0
DS
1246}
1247
d3dd1804
DS
1248/*
1249 * When we have a new neighbor,
1250 * find upstreams that don't have their rpf_addr
1251 * set and see if the new neighbor allows
1252 * the join to be sent
1253 */
1254void
1255pim_upstream_find_new_rpf (void)
1256{
1257 struct listnode *up_node;
1258 struct listnode *up_nextnode;
1259 struct pim_upstream *up;
1260
1261 /*
0f588989
DS
1262 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1263 */
1264 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1265 {
63c59d0c 1266 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804
DS
1267 {
1268 if (PIM_DEBUG_PIM_TRACE)
1269 zlog_debug ("Upstream %s without a path to send join, checking",
1270 pim_str_sg_dump (&up->sg));
1271 pim_rpf_update (up, NULL);
1272 }
1273 }
1274}
0f588989 1275
0f588989
DS
1276static unsigned int
1277pim_upstream_hash_key (void *arg)
1278{
1279 struct pim_upstream *up = (struct pim_upstream *)arg;
1280
1281 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1282}
1283
1284void pim_upstream_terminate (void)
1285{
1286 if (pim_upstream_list)
1287 list_free (pim_upstream_list);
1288 pim_upstream_list = NULL;
1289
1290 if (pim_upstream_hash)
1291 hash_free (pim_upstream_hash);
1292}
1293
1294static int
1295pim_upstream_equal (const void *arg1, const void *arg2)
1296{
1297 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1298 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1299
1300 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1301 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1302 return 1;
1303
1304 return 0;
1305}
1306
9c5e4d62
DS
1307/*
1308 * Code to check and see if we've received packets on a S,G mroute
1309 * and if so to set the SPT bit appropriately
1310 */
1311static void
1312pim_upstream_sg_running (void *arg)
1313{
1314 struct pim_upstream *up = (struct pim_upstream *)arg;
e43b8697
DS
1315 long long now;
1316
1317 // If we are TRUE already no need to do more work
1318 if (up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
1319 {
1320 if (PIM_DEBUG_TRACE)
1321 zlog_debug ("%s: %s sptbit is true", __PRETTY_FUNCTION__,
1322 pim_str_sg_dump(&up->sg));
1323 return;
1324 }
1325
1326 // No packet can have arrived here if this is the case
1327 if (!up->channel_oil || !up->channel_oil->installed)
1328 {
1329 if (PIM_DEBUG_TRACE)
1330 zlog_debug ("%s: %s is not installed in mroute",
1331 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg));
1332 return;
1333 }
1334
1335 // We need at least 30 seconds to see if we are getting packets
1336 now = pim_time_monotonic_sec();
1337 if (now - up->state_transition <= 30)
1338 {
1339 if (PIM_DEBUG_TRACE)
1340 zlog_debug ("%s: %s uptime is %lld",
1341 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg),
1342 now - up->state_transition);
1343 return;
1344 }
1345
1346 pim_mroute_update_counters (up->channel_oil);
1347
1348 // Have we seen packets?
1349 if ((up->channel_oil->cc.oldpktcnt <= up->channel_oil->cc.pktcnt) &&
1350 (up->channel_oil->cc.lastused/100 > 30))
1351 {
1352 if (PIM_DEBUG_TRACE)
1353 {
1354 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30",
1355 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg));
1356 zlog_debug ("%s: %ld %ld %lld", __PRETTY_FUNCTION__, up->channel_oil->cc.oldpktcnt, up->channel_oil->cc.pktcnt, up->channel_oil->cc.lastused/100);
1357 }
1358 return;
1359 }
1360
3a66b17b 1361 pim_upstream_set_sptbit (up, up->rpf.source_nexthop.interface);
e43b8697 1362 return;
9c5e4d62
DS
1363}
1364
040d86ad
DS
1365void
1366pim_upstream_init (void)
0f588989 1367{
9c5e4d62
DS
1368 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1369 pim_upstream_hash_key,
1370 pim_upstream_sg_running);
0f588989
DS
1371 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1372 pim_upstream_equal);
1373
1374 pim_upstream_list = list_new ();
1375 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1376 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1377
1378}