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