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