]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Reduce RP checks a bit
[mirror_frr.git] / pimd / pim_upstream.c
CommitLineData
12e41d03 1/*
896014f4
DL
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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
12e41d03
DL
19
20#include <zebra.h>
21
12e41d03
DL
22#include "log.h"
23#include "zclient.h"
24#include "memory.h"
25#include "thread.h"
26#include "linklist.h"
dfe43e25
DW
27#include "vty.h"
28#include "plist.h"
0f588989
DS
29#include "hash.h"
30#include "jhash.h"
9c5e4d62 31#include "wheel.h"
12e41d03
DL
32
33#include "pimd.h"
34#include "pim_pim.h"
35#include "pim_str.h"
36#include "pim_time.h"
37#include "pim_iface.h"
38#include "pim_join.h"
39#include "pim_zlookup.h"
40#include "pim_upstream.h"
41#include "pim_ifchannel.h"
42#include "pim_neighbor.h"
43#include "pim_rpf.h"
44#include "pim_zebra.h"
45#include "pim_oil.h"
46#include "pim_macro.h"
8f5f5e91 47#include "pim_rp.h"
f14248dd 48#include "pim_br.h"
627ed2a3 49#include "pim_register.h"
3c72d654 50#include "pim_msdp.h"
982bff89 51#include "pim_jp_agg.h"
1bc98276 52#include "pim_nht.h"
15a5dafe 53#include "pim_ssm.h"
12e41d03 54
982bff89 55static void join_timer_stop(struct pim_upstream *up);
d62a17ae 56static void
57pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
12e41d03 58
cfa91a87
DS
59/*
60 * A (*,G) or a (*,*) is going away
61 * remove the parent pointer from
62 * those pointing at us
63 */
9b29ea95
DS
64static void pim_upstream_remove_children(struct pim_instance *pim,
65 struct pim_upstream *up)
cfa91a87 66{
d62a17ae 67 struct pim_upstream *child;
68
69 if (!up->sources)
70 return;
71
72 while (!list_isempty(up->sources)) {
73 child = listnode_head(up->sources);
74 listnode_delete(up->sources, child);
75 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) {
76 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
9b29ea95
DS
77 child = pim_upstream_del(pim, child,
78 __PRETTY_FUNCTION__);
d62a17ae 79 }
80 if (child)
81 child->parent = NULL;
82 }
6a154c88 83 list_delete(&up->sources);
cfa91a87
DS
84}
85
86/*
87 * A (*,G) or a (*,*) is being created
88 * Find the children that would point
89 * at us.
90 */
9b29ea95
DS
91static void pim_upstream_find_new_children(struct pim_instance *pim,
92 struct pim_upstream *up)
cfa91a87 93{
d62a17ae 94 struct pim_upstream *child;
95 struct listnode *ch_node;
96
97 if ((up->sg.src.s_addr != INADDR_ANY)
98 && (up->sg.grp.s_addr != INADDR_ANY))
99 return;
100
101 if ((up->sg.src.s_addr == INADDR_ANY)
102 && (up->sg.grp.s_addr == INADDR_ANY))
103 return;
104
9b29ea95 105 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, ch_node, child)) {
d62a17ae 106 if ((up->sg.grp.s_addr != INADDR_ANY)
107 && (child->sg.grp.s_addr == up->sg.grp.s_addr)
108 && (child != up)) {
109 child->parent = up;
110 listnode_add_sort(up->sources, child);
111 }
03417ccd 112 }
cfa91a87
DS
113}
114
4d99418b
DS
115/*
116 * If we have a (*,*) || (S,*) there is no parent
117 * If we have a (S,G), find the (*,G)
118 * If we have a (*,G), find the (*,*)
119 */
9b29ea95
DS
120static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim,
121 struct pim_upstream *child)
4d99418b 122{
d62a17ae 123 struct prefix_sg any = child->sg;
124 struct pim_upstream *up = NULL;
4d99418b 125
d62a17ae 126 // (S,G)
127 if ((child->sg.src.s_addr != INADDR_ANY)
128 && (child->sg.grp.s_addr != INADDR_ANY)) {
129 any.src.s_addr = INADDR_ANY;
9b29ea95 130 up = pim_upstream_find(pim, &any);
03417ccd 131
d62a17ae 132 if (up)
133 listnode_add(up->sources, child);
03417ccd 134
d62a17ae 135 return up;
136 }
4d99418b 137
d62a17ae 138 return NULL;
4d99418b
DS
139}
140
12e41d03
DL
141static void upstream_channel_oil_detach(struct pim_upstream *up)
142{
d62a17ae 143 if (up->channel_oil) {
144 /* Detaching from channel_oil, channel_oil may exist post del,
145 but upstream would not keep reference of it
146 */
13221cf2 147 up->channel_oil->up = NULL;
d62a17ae 148 pim_channel_oil_del(up->channel_oil);
149 up->channel_oil = NULL;
150 }
12e41d03
DL
151}
152
9b29ea95
DS
153struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
154 struct pim_upstream *up, const char *name)
12e41d03 155{
7692c5ae
DS
156 struct listnode *node, *nnode;
157 struct pim_ifchannel *ch;
d62a17ae 158 bool notify_msdp = false;
159 struct prefix nht_p;
160
161 if (PIM_DEBUG_TRACE)
162 zlog_debug(
8dbdb215 163 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
996c9314
LB
164 __PRETTY_FUNCTION__, name, up->sg_str, pim->vrf->name,
165 up->ref_count, up->flags,
166 up->channel_oil->oil_ref_count);
d62a17ae 167
e83f3b31 168 assert(up->ref_count > 0);
169
d62a17ae 170 --up->ref_count;
171
172 if (up->ref_count >= 1)
173 return up;
174
175 THREAD_OFF(up->t_ka_timer);
176 THREAD_OFF(up->t_rs_timer);
177 THREAD_OFF(up->t_msdp_reg_timer);
178
179 if (up->join_state == PIM_UPSTREAM_JOINED) {
180 pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
181
182 if (up->sg.src.s_addr == INADDR_ANY) {
183 /* if a (*, G) entry in the joined state is being
184 * deleted we
185 * need to notify MSDP */
186 notify_msdp = true;
187 }
188 }
189
190 join_timer_stop(up);
191 pim_jp_agg_upstream_verification(up, false);
192 up->rpf.source_nexthop.interface = NULL;
193
194 if (up->sg.src.s_addr != INADDR_ANY) {
391b8b08
DS
195 if (pim->upstream_sg_wheel)
196 wheel_remove_item(pim->upstream_sg_wheel, up);
d62a17ae 197 notify_msdp = true;
198 }
199
d62a17ae 200 pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
201 upstream_channel_oil_detach(up);
202
7692c5ae
DS
203 for (ALL_LIST_ELEMENTS(up->ifchannels, node, nnode, ch))
204 pim_ifchannel_delete(ch);
6a154c88 205 list_delete(&up->ifchannels);
d62a17ae 206
7692c5ae
DS
207 pim_upstream_remove_children(pim, up);
208 if (up->sources)
6a154c88 209 list_delete(&up->sources);
7692c5ae 210
d62a17ae 211 if (up->parent && up->parent->sources)
212 listnode_delete(up->parent->sources, up);
213 up->parent = NULL;
214
9b29ea95
DS
215 listnode_delete(pim->upstream_list, up);
216 hash_release(pim->upstream_hash, up);
d62a17ae 217
218 if (notify_msdp) {
472ad383 219 pim_msdp_up_del(pim, &up->sg);
d62a17ae 220 }
221
246445a3
SP
222 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
223 * and assign up->upstream_addr as INADDR_ANY.
224 * So before de-registering the upstream address, check if is not equal
225 * to INADDR_ANY. This is done in order to avoid de-registering for
226 * 255.255.255.255 which is maintained for some reason..
227 */
228 if (up->upstream_addr.s_addr != INADDR_ANY) {
229 /* Deregister addr with Zebra NHT */
230 nht_p.family = AF_INET;
231 nht_p.prefixlen = IPV4_MAX_BITLEN;
232 nht_p.u.prefix4 = up->upstream_addr;
233 if (PIM_DEBUG_TRACE) {
234 char buf[PREFIX2STR_BUFFER];
235 prefix2str(&nht_p, buf, sizeof(buf));
236 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
237 __PRETTY_FUNCTION__, up->sg_str, buf);
238 }
239 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
d62a17ae 240 }
d62a17ae 241
172e45dc 242 XFREE(MTYPE_PIM_UPSTREAM, up);
d62a17ae 243
244 return NULL;
12e41d03
DL
245}
246
d62a17ae 247void pim_upstream_send_join(struct pim_upstream *up)
12e41d03 248{
957d93ea
SP
249 if (!up->rpf.source_nexthop.interface) {
250 if (PIM_DEBUG_TRACE)
251 zlog_debug("%s: up %s RPF is not present",
252 __PRETTY_FUNCTION__, up->sg_str);
253 return;
254 }
255
d62a17ae 256 if (PIM_DEBUG_TRACE) {
257 char rpf_str[PREFIX_STRLEN];
258 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
259 sizeof(rpf_str));
260 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
261 __PRETTY_FUNCTION__, up->sg_str, rpf_str,
262 pim_upstream_state2str(up->join_state),
263 up->rpf.source_nexthop.interface->name);
264 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
265 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
266 __PRETTY_FUNCTION__, up->sg_str, rpf_str);
267 /* warning only */
268 }
269 }
270
271 /* send Join(S,G) to the current upstream neighbor */
272 pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
12e41d03
DL
273}
274
275static int on_join_timer(struct thread *t)
276{
d62a17ae 277 struct pim_upstream *up;
12e41d03 278
d62a17ae 279 up = THREAD_ARG(t);
12e41d03 280
957d93ea
SP
281 if (!up->rpf.source_nexthop.interface) {
282 if (PIM_DEBUG_TRACE)
283 zlog_debug("%s: up %s RPF is not present",
284 __PRETTY_FUNCTION__, up->sg_str);
285 return 0;
286 }
287
d62a17ae 288 /*
289 * In the case of a HFR we will not ahve anyone to send this to.
290 */
291 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
292 return 0;
bb6e291f 293
d62a17ae 294 /*
295 * Don't send the join if the outgoing interface is a loopback
296 * But since this might change leave the join timer running
297 */
298 if (up->rpf.source_nexthop
299 .interface && !if_is_loopback(up->rpf.source_nexthop.interface))
300 pim_upstream_send_join(up);
12e41d03 301
d62a17ae 302 join_timer_start(up);
12e41d03 303
d62a17ae 304 return 0;
12e41d03
DL
305}
306
982bff89 307static void join_timer_stop(struct pim_upstream *up)
12e41d03 308{
47e3ce59 309 struct pim_neighbor *nbr = NULL;
957d93ea 310
d62a17ae 311 THREAD_OFF(up->t_join_timer);
7eb90689 312
47e3ce59
SP
313 if (up->rpf.source_nexthop.interface)
314 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
315 up->rpf.rpf_addr.u.prefix4);
982bff89 316
d62a17ae 317 if (nbr)
318 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
982bff89 319
d62a17ae 320 pim_jp_agg_upstream_verification(up, false);
982bff89
DS
321}
322
d62a17ae 323void join_timer_start(struct pim_upstream *up)
982bff89 324{
d62a17ae 325 struct pim_neighbor *nbr = NULL;
326
327 if (up->rpf.source_nexthop.interface) {
328 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
329 up->rpf.rpf_addr.u.prefix4);
330
331 if (PIM_DEBUG_PIM_EVENTS) {
332 zlog_debug(
333 "%s: starting %d sec timer for upstream (S,G)=%s",
5b45753e 334 __PRETTY_FUNCTION__, router->t_periodic,
d62a17ae 335 up->sg_str);
336 }
337 }
338
339 if (nbr)
340 pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1);
341 else {
342 THREAD_OFF(up->t_join_timer);
36417fcc 343 thread_add_timer(router->master, on_join_timer, up,
5b45753e 344 router->t_periodic, &up->t_join_timer);
d62a17ae 345 }
346 pim_jp_agg_upstream_verification(up, true);
12e41d03
DL
347}
348
982bff89
DS
349/*
350 * This is only called when we are switching the upstream
351 * J/P from one neighbor to another
352 *
353 * As such we need to remove from the old list and
354 * add to the new list.
355 */
d62a17ae 356void pim_upstream_join_timer_restart(struct pim_upstream *up,
357 struct pim_rpf *old)
12e41d03 358{
d62a17ae 359 // THREAD_OFF(up->t_join_timer);
360 join_timer_start(up);
12e41d03
DL
361}
362
363static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
364 int interval_msec)
365{
d62a17ae 366 if (PIM_DEBUG_PIM_EVENTS) {
367 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
368 __PRETTY_FUNCTION__, interval_msec, up->sg_str);
369 }
370
371 THREAD_OFF(up->t_join_timer);
36417fcc 372 thread_add_timer_msec(router->master, on_join_timer, up, interval_msec,
d62a17ae 373 &up->t_join_timer);
12e41d03
DL
374}
375
376void pim_upstream_join_suppress(struct pim_upstream *up,
d62a17ae 377 struct in_addr rpf_addr, int holdtime)
12e41d03 378{
d62a17ae 379 long t_joinsuppress_msec;
380 long join_timer_remain_msec;
381
957d93ea
SP
382 if (!up->rpf.source_nexthop.interface) {
383 if (PIM_DEBUG_TRACE)
384 zlog_debug("%s: up %s RPF is not present",
385 __PRETTY_FUNCTION__, up->sg_str);
386 return;
387 }
388
d62a17ae 389 t_joinsuppress_msec =
390 MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
391 1000 * holdtime);
392
393 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
394
395 if (PIM_DEBUG_TRACE) {
396 char rpf_str[INET_ADDRSTRLEN];
397 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
398 zlog_debug(
399 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
400 __FILE__, __PRETTY_FUNCTION__, up->sg_str, rpf_str,
401 join_timer_remain_msec, t_joinsuppress_msec);
402 }
403
404 if (join_timer_remain_msec < t_joinsuppress_msec) {
405 if (PIM_DEBUG_TRACE) {
406 zlog_debug(
407 "%s %s: suppressing Join(S,G)=%s for %ld msec",
408 __FILE__, __PRETTY_FUNCTION__, up->sg_str,
409 t_joinsuppress_msec);
410 }
411
412 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
413 }
12e41d03
DL
414}
415
416void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
d62a17ae 417 struct pim_upstream *up)
12e41d03 418{
d62a17ae 419 long join_timer_remain_msec;
420 int t_override_msec;
421
957d93ea
SP
422 if (!up->rpf.source_nexthop.interface) {
423 if (PIM_DEBUG_TRACE)
424 zlog_debug("%s: up %s RPF is not present",
425 __PRETTY_FUNCTION__, up->sg_str);
426 return;
427 }
428
d62a17ae 429 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
430 t_override_msec =
431 pim_if_t_override_msec(up->rpf.source_nexthop.interface);
432
433 if (PIM_DEBUG_TRACE) {
434 char rpf_str[INET_ADDRSTRLEN];
435 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str,
436 sizeof(rpf_str));
437 zlog_debug(
438 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
439 debug_label, up->sg_str, rpf_str,
440 join_timer_remain_msec, t_override_msec);
441 }
442
443 if (join_timer_remain_msec > t_override_msec) {
444 if (PIM_DEBUG_TRACE) {
445 zlog_debug(
446 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
447 debug_label, up->sg_str, t_override_msec);
448 }
449
450 pim_upstream_join_timer_restart_msec(up, t_override_msec);
451 }
12e41d03
DL
452}
453
454static void forward_on(struct pim_upstream *up)
455{
d62a17ae 456 struct listnode *chnode;
457 struct listnode *chnextnode;
458 struct pim_ifchannel *ch = NULL;
12e41d03 459
d62a17ae 460 /* scan (S,G) state */
461 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
462 if (pim_macro_chisin_oiflist(ch))
463 pim_forward_start(ch);
12e41d03 464
d62a17ae 465 } /* scan iface channel list */
12e41d03
DL
466}
467
468static void forward_off(struct pim_upstream *up)
469{
d62a17ae 470 struct listnode *chnode;
471 struct listnode *chnextnode;
472 struct pim_ifchannel *ch;
12e41d03 473
d62a17ae 474 /* scan per-interface (S,G) state */
475 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
12e41d03 476
aabb9a2f 477 pim_forward_stop(ch, false);
12e41d03 478
d62a17ae 479 } /* scan iface channel list */
12e41d03
DL
480}
481
d62a17ae 482static int pim_upstream_could_register(struct pim_upstream *up)
bb6e291f 483{
d62a17ae 484 struct pim_interface *pim_ifp = NULL;
485
486 if (up->rpf.source_nexthop.interface)
487 pim_ifp = up->rpf.source_nexthop.interface->info;
488 else {
489 if (PIM_DEBUG_TRACE)
490 zlog_debug("%s: up %s RPF is not present",
491 __PRETTY_FUNCTION__, up->sg_str);
492 }
bb6e291f 493
d62a17ae 494 if (pim_ifp && PIM_I_am_DR(pim_ifp)
495 && pim_if_connected_to_source(up->rpf.source_nexthop.interface,
496 up->sg.src))
497 return 1;
bb6e291f 498
d62a17ae 499 return 0;
bb6e291f
DS
500}
501
0437e105 502/* Source registration is suppressed for SSM groups. When the SSM range changes
15a5dafe 503 * we re-revaluate register setup for existing upstream entries */
9b29ea95 504void pim_upstream_register_reevaluate(struct pim_instance *pim)
15a5dafe 505{
d62a17ae 506 struct listnode *upnode;
507 struct pim_upstream *up;
508
9b29ea95 509 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
d62a17ae 510 /* If FHR is set CouldRegister is True. Also check if the flow
511 * is actually active; if it is not kat setup will trigger
512 * source
513 * registration whenever the flow becomes active. */
514 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || !up->t_ka_timer)
515 continue;
516
6f439a70 517 if (pim_is_grp_ssm(pim, up->sg.grp)) {
d62a17ae 518 /* clear the register state for SSM groups */
519 if (up->reg_state != PIM_REG_NOINFO) {
520 if (PIM_DEBUG_PIM_EVENTS)
521 zlog_debug(
522 "Clear register for %s as G is now SSM",
523 up->sg_str);
524 /* remove regiface from the OIL if it is there*/
525 pim_channel_del_oif(up->channel_oil,
9b29ea95 526 pim->regiface,
d62a17ae 527 PIM_OIF_FLAG_PROTO_PIM);
528 up->reg_state = PIM_REG_NOINFO;
529 }
530 } else {
531 /* register ASM sources with the RP */
532 if (up->reg_state == PIM_REG_NOINFO) {
533 if (PIM_DEBUG_PIM_EVENTS)
534 zlog_debug(
535 "Register %s as G is now ASM",
536 up->sg_str);
537 pim_channel_add_oif(up->channel_oil,
9b29ea95 538 pim->regiface,
d62a17ae 539 PIM_OIF_FLAG_PROTO_PIM);
540 up->reg_state = PIM_REG_JOIN;
541 }
542 }
543 }
15a5dafe 544}
545
1eca8576 546void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
d62a17ae 547 enum pim_upstream_state new_state)
12e41d03 548{
d62a17ae 549 enum pim_upstream_state old_state = up->join_state;
550
957d93ea 551 if (up->upstream_addr.s_addr == INADDR_ANY) {
47e3ce59
SP
552 if (PIM_DEBUG_PIM_EVENTS)
553 zlog_debug("%s: RPF not configured for %s",
554 __PRETTY_FUNCTION__, up->sg_str);
957d93ea
SP
555 return;
556 }
557
558 if (!up->rpf.source_nexthop.interface) {
47e3ce59
SP
559 if (PIM_DEBUG_PIM_EVENTS)
560 zlog_debug("%s: RP not reachable for %s",
561 __PRETTY_FUNCTION__, up->sg_str);
957d93ea
SP
562 return;
563 }
564
d62a17ae 565 if (PIM_DEBUG_PIM_EVENTS) {
566 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
567 __PRETTY_FUNCTION__, up->sg_str,
568 pim_upstream_state2str(up->join_state),
569 pim_upstream_state2str(new_state));
570 }
571
572 up->join_state = new_state;
573 if (old_state != new_state)
574 up->state_transition = pim_time_monotonic_sec();
575
576 pim_upstream_update_assert_tracking_desired(up);
577
578 if (new_state == PIM_UPSTREAM_JOINED) {
579 if (old_state != PIM_UPSTREAM_JOINED) {
580 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
581 forward_on(up);
1eca8576 582 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 583 if (pim_upstream_could_register(up)) {
584 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
585 if (!old_fhr
586 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
587 up->flags)) {
588 pim_upstream_keep_alive_timer_start(
19b807ca 589 up, pim->keep_alive_time);
d62a17ae 590 pim_register_join(up);
591 }
592 } else {
593 pim_upstream_send_join(up);
594 join_timer_start(up);
595 }
596 } else {
597 forward_on(up);
598 }
599 } else {
600
601 forward_off(up);
602 if (old_state == PIM_UPSTREAM_JOINED)
1eca8576 603 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 604
605 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
606 RP.
607 If I am RP for G then send S,G prune to its IIF. */
608 if (pim_upstream_is_sg_rpt(up) && up->parent
1eca8576 609 && !I_am_RP(pim, up->sg.grp)) {
d62a17ae 610 if (PIM_DEBUG_PIM_TRACE_DETAIL)
611 zlog_debug(
957d93ea
SP
612 "%s: *,G IIF %s S,G IIF %s ",
613 __PRETTY_FUNCTION__,
614 up->parent->rpf.source_nexthop.interface ?
615 up->parent->rpf.source_nexthop.interface->name
616 : "Unknown",
617 up->rpf.source_nexthop.interface ?
618 up->rpf.source_nexthop.interface->name :
619 "Unknown");
d62a17ae 620 pim_jp_agg_single_upstream_send(&up->parent->rpf,
621 up->parent,
622 1 /* (W,G) Join */);
623 } else
624 pim_jp_agg_single_upstream_send(&up->rpf, up,
625 0 /* prune */);
626 join_timer_stop(up);
627 }
12e41d03
DL
628}
629
d62a17ae 630int pim_upstream_compare(void *arg1, void *arg2)
03417ccd 631{
d62a17ae 632 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
633 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
03417ccd 634
d62a17ae 635 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
636 return -1;
03417ccd 637
d62a17ae 638 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
639 return 1;
03417ccd 640
d62a17ae 641 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
642 return -1;
03417ccd 643
d62a17ae 644 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
645 return 1;
03417ccd 646
d62a17ae 647 return 0;
03417ccd
DS
648}
649
2002dcdb
DS
650static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
651 struct prefix_sg *sg,
652 struct interface *incoming,
0885a9f1
DS
653 int flags,
654 struct pim_ifchannel *ch)
12e41d03 655{
d62a17ae 656 enum pim_rpf_result rpf_result;
657 struct pim_interface *pim_ifp;
658 struct pim_upstream *up;
659
660 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
d62a17ae 661
662 up->sg = *sg;
663 pim_str_sg_set(sg, up->sg_str);
0885a9f1
DS
664 if (ch)
665 ch->upstream = up;
666
9b29ea95 667 up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
732c209c
SP
668 /* Set up->upstream_addr as INADDR_ANY, if RP is not
669 * configured and retain the upstream data structure
670 */
d9c9a9ee
DS
671 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
672 sg->grp)) {
d62a17ae 673 if (PIM_DEBUG_TRACE)
674 zlog_debug("%s: Received a (*,G) with no RP configured",
675 __PRETTY_FUNCTION__);
d62a17ae 676 }
677
9b29ea95 678 up->parent = pim_upstream_find_parent(pim, up);
d62a17ae 679 if (up->sg.src.s_addr == INADDR_ANY) {
680 up->sources = list_new();
681 up->sources->cmp = pim_upstream_compare;
682 } else
683 up->sources = NULL;
684
9b29ea95 685 pim_upstream_find_new_children(pim, up);
d62a17ae 686 up->flags = flags;
687 up->ref_count = 1;
688 up->t_join_timer = NULL;
689 up->t_ka_timer = NULL;
690 up->t_rs_timer = NULL;
691 up->t_msdp_reg_timer = NULL;
692 up->join_state = PIM_UPSTREAM_NOTJOINED;
693 up->reg_state = PIM_REG_NOINFO;
694 up->state_transition = pim_time_monotonic_sec();
695 up->channel_oil = NULL;
696 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
697
698 up->rpf.source_nexthop.interface = NULL;
699 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
700 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
701 PIM_NET_INADDR_ANY;
702 up->rpf.source_nexthop.mrib_metric_preference =
d17612dd 703 router->infinite_assert_metric.metric_preference;
d62a17ae 704 up->rpf.source_nexthop.mrib_route_metric =
d17612dd 705 router->infinite_assert_metric.route_metric;
d62a17ae 706 up->rpf.rpf_addr.family = AF_INET;
707 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
708
709 up->ifchannels = list_new();
710 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
711
712 if (up->sg.src.s_addr != INADDR_ANY)
9b29ea95 713 wheel_add_item(pim->upstream_sg_wheel, up);
d62a17ae 714
732c209c
SP
715 if (up->upstream_addr.s_addr == INADDR_ANY)
716 /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
717 * since RP is not configured
718 */
719 up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS);
d62a17ae 720
732c209c
SP
721 else {
722 rpf_result = pim_rpf_update(pim, up, NULL, 1);
723 if (rpf_result == PIM_RPF_FAILURE) {
724 if (PIM_DEBUG_TRACE)
725 zlog_debug(
726 "%s: Attempting to create upstream(%s), Unable to RPF for source",
727 __PRETTY_FUNCTION__, up->sg_str);
728 /* Create a dummmy channel oil with incoming ineterface
729 * MAXVIFS, since RP is not reachable
730 */
731 up->channel_oil = pim_channel_oil_add(
732 pim, &up->sg, MAXVIFS);
d62a17ae 733 }
734
732c209c
SP
735 if (up->rpf.source_nexthop.interface) {
736 pim_ifp = up->rpf.source_nexthop.interface->info;
737 if (pim_ifp)
738 up->channel_oil = pim_channel_oil_add(pim,
739 &up->sg, pim_ifp->mroute_vif_index);
740 }
d62a17ae 741 }
742
9b29ea95 743 listnode_add_sort(pim->upstream_list, up);
d62a17ae 744
745 if (PIM_DEBUG_TRACE) {
746 zlog_debug(
747 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
748 __PRETTY_FUNCTION__, up->sg_str,
749 inet_ntoa(up->upstream_addr), up->ref_count);
750 }
751
752 return up;
12e41d03
DL
753}
754
9b29ea95
DS
755struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
756 struct prefix_sg *sg)
12e41d03 757{
d62a17ae 758 struct pim_upstream lookup;
759 struct pim_upstream *up = NULL;
12e41d03 760
d62a17ae 761 lookup.sg = *sg;
9b29ea95 762 up = hash_lookup(pim->upstream_hash, &lookup);
d62a17ae 763 return up;
12e41d03
DL
764}
765
d62a17ae 766struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
767 struct interface *incoming,
768 int flags, const char *name)
e711cd3c 769{
d62a17ae 770 struct pim_upstream *up;
9b29ea95
DS
771 struct pim_interface *pim_ifp;
772
773 pim_ifp = incoming->info;
d62a17ae 774
9b29ea95 775 up = pim_upstream_find(pim_ifp->pim, sg);
d62a17ae 776
777 if (up) {
778 if (!(up->flags & flags)) {
779 up->flags |= flags;
780 up->ref_count++;
781 if (PIM_DEBUG_TRACE)
782 zlog_debug(
783 "%s(%s): upstream %s ref count %d increment",
784 __PRETTY_FUNCTION__, name, up->sg_str,
785 up->ref_count);
786 }
787 } else
0885a9f1
DS
788 up = pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
789 NULL);
d62a17ae 790
791 return up;
e711cd3c
DS
792}
793
d62a17ae 794void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1bf16443 795{
d62a17ae 796 up->flags |= flags;
797 ++up->ref_count;
798 if (PIM_DEBUG_TRACE)
799 zlog_debug("%s(%s): upstream %s ref count %d increment",
800 __PRETTY_FUNCTION__, name, up->sg_str,
801 up->ref_count);
1bf16443 802}
803
2002dcdb
DS
804struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
805 struct prefix_sg *sg,
d62a17ae 806 struct interface *incoming, int flags,
0885a9f1
DS
807 const char *name,
808 struct pim_ifchannel *ch)
12e41d03 809{
d62a17ae 810 struct pim_upstream *up = NULL;
811 int found = 0;
9b29ea95 812
2002dcdb 813 up = pim_upstream_find(pim, sg);
d62a17ae 814 if (up) {
815 pim_upstream_ref(up, flags, name);
816 found = 1;
817 } else {
0885a9f1 818 up = pim_upstream_new(pim, sg, incoming, flags, ch);
d62a17ae 819 }
820
821 if (PIM_DEBUG_TRACE) {
822 if (up) {
823 char buf[PREFIX2STR_BUFFER];
824 prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf));
825 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
f4075cb4 826 __PRETTY_FUNCTION__, name,
55785900 827 up->sg_str, buf, up->rpf.source_nexthop.interface ?
957d93ea 828 up->rpf.source_nexthop.interface->name : "Unknown" ,
55785900 829 found, up->ref_count);
d62a17ae 830 } else
831 zlog_debug("%s(%s): (%s) failure to create",
832 __PRETTY_FUNCTION__, name,
833 pim_str_sg_dump(sg));
834 }
12e41d03 835
d62a17ae 836 return up;
12e41d03
DL
837}
838
c8fc07cb
DS
839/*
840 * Passed in up must be the upstream for ch. starch is NULL if no
841 * information
842 */
d62a17ae 843int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
844 struct pim_ifchannel *ch,
845 struct pim_ifchannel *starch)
7a3ddda5 846{
d62a17ae 847 if (ch) {
848 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
849 return 0;
850
851 if (!pim_macro_ch_lost_assert(ch)
852 && pim_macro_chisin_joins_or_include(ch))
853 return 1;
854 }
855
856 /*
857 * joins (*,G)
858 */
859 if (starch) {
860 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
861 return 0;
862
863 if (!pim_macro_ch_lost_assert(starch)
864 && pim_macro_chisin_joins_or_include(starch))
865 return 1;
866 }
867
868 return 0;
7a3ddda5
DS
869}
870
12e41d03
DL
871/*
872 Evaluate JoinDesired(S,G):
873
874 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
875 in the set:
876
877 inherited_olist(S,G) =
878 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
879
880 JoinDesired(S,G) may be affected by changes in the following:
881
882 pim_ifp->primary_address
883 pim_ifp->pim_dr_addr
884 ch->ifassert_winner_metric
885 ch->ifassert_winner
d62a17ae 886 ch->local_ifmembership
12e41d03
DL
887 ch->ifjoin_state
888 ch->upstream->rpf.source_nexthop.mrib_metric_preference
889 ch->upstream->rpf.source_nexthop.mrib_route_metric
890 ch->upstream->rpf.source_nexthop.interface
891
892 See also pim_upstream_update_join_desired() below.
893 */
9b29ea95
DS
894int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
895 struct pim_upstream *up)
12e41d03 896{
d62a17ae 897 struct interface *ifp;
d62a17ae 898 struct pim_ifchannel *ch, *starch;
899 struct pim_upstream *starup = up->parent;
900 int ret = 0;
12e41d03 901
451fda4f 902 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 903 if (!ifp->info)
904 continue;
c8fc07cb 905
d62a17ae 906 ch = pim_ifchannel_find(ifp, &up->sg);
c8fc07cb 907
d62a17ae 908 if (starup)
909 starch = pim_ifchannel_find(ifp, &starup->sg);
910 else
911 starch = NULL;
c8fc07cb 912
d62a17ae 913 if (!ch && !starch)
914 continue;
12e41d03 915
d62a17ae 916 ret += pim_upstream_evaluate_join_desired_interface(up, ch,
917 starch);
918 } /* scan iface channel list */
12e41d03 919
d62a17ae 920 return ret; /* false */
12e41d03
DL
921}
922
923/*
924 See also pim_upstream_evaluate_join_desired() above.
925*/
9b29ea95
DS
926void pim_upstream_update_join_desired(struct pim_instance *pim,
927 struct pim_upstream *up)
12e41d03 928{
d62a17ae 929 int was_join_desired; /* boolean */
930 int is_join_desired; /* boolean */
931
932 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
933
9b29ea95 934 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
d62a17ae 935 if (is_join_desired)
936 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
937 else
938 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
939
940 /* switched from false to true */
47e3ce59 941 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1eca8576 942 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 943 return;
944 }
945
946 /* switched from true to false */
947 if (!is_join_desired && was_join_desired) {
1eca8576 948 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
d62a17ae 949 return;
950 }
12e41d03
DL
951}
952
953/*
954 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
955 Transitions from Joined State
956 RPF'(S,G) GenID changes
957
958 The upstream (S,G) state machine remains in Joined state. If the
959 Join Timer is set to expire in more than t_override seconds, reset
960 it so that it expires after t_override seconds.
961*/
9b29ea95
DS
962void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
963 struct in_addr neigh_addr)
12e41d03 964{
d62a17ae 965 struct listnode *up_node;
966 struct listnode *up_nextnode;
967 struct pim_upstream *up;
968
969 /*
970 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
971 */
9b29ea95 972 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
d62a17ae 973
974 if (PIM_DEBUG_TRACE) {
975 char neigh_str[INET_ADDRSTRLEN];
976 char rpf_addr_str[PREFIX_STRLEN];
977 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
978 sizeof(neigh_str));
979 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
980 sizeof(rpf_addr_str));
981 zlog_debug(
8dbdb215 982 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
996c9314
LB
983 __PRETTY_FUNCTION__, neigh_str, up->sg_str,
984 pim->vrf->name,
d62a17ae 985 up->join_state == PIM_UPSTREAM_JOINED,
986 rpf_addr_str);
987 }
988
989 /* consider only (S,G) upstream in Joined state */
990 if (up->join_state != PIM_UPSTREAM_JOINED)
991 continue;
992
993 /* match RPF'(S,G)=neigh_addr */
994 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
995 continue;
996
997 pim_upstream_join_timer_decrease_to_t_override(
998 "RPF'(S,G) GenID change", up);
999 }
12e41d03
DL
1000}
1001
1002
1003void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1004 struct interface *old_rpf_ifp)
1005{
d62a17ae 1006 struct listnode *chnode;
1007 struct listnode *chnextnode;
1008 struct pim_ifchannel *ch;
1009
1010 /* search all ifchannels */
1011 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1012 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1013 if (
1014 /* RPF_interface(S) was NOT I */
1015 (old_rpf_ifp == ch->interface) &&
1016 /* RPF_interface(S) stopped being I */
1017 (ch->upstream->rpf.source_nexthop
957d93ea
SP
1018 .interface) &&
1019 (ch->upstream->rpf.source_nexthop
1020 .interface != ch->interface)) {
d62a17ae 1021 assert_action_a5(ch);
1022 }
1023 } /* PIM_IFASSERT_I_AM_LOSER */
1024
1025 pim_ifchannel_update_assert_tracking_desired(ch);
1026 }
12e41d03
DL
1027}
1028
1029void pim_upstream_update_could_assert(struct pim_upstream *up)
1030{
d62a17ae 1031 struct listnode *chnode;
1032 struct listnode *chnextnode;
1033 struct pim_ifchannel *ch;
1034
1035 /* scan per-interface (S,G) state */
1036 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1037 pim_ifchannel_update_could_assert(ch);
1038 } /* scan iface channel list */
12e41d03
DL
1039}
1040
1041void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1042{
d62a17ae 1043 struct listnode *chnode;
1044 struct listnode *chnextnode;
1045 struct pim_ifchannel *ch;
12e41d03 1046
d62a17ae 1047 /* scan per-interface (S,G) state */
1048 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1049 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 1050
d62a17ae 1051 } /* scan iface channel list */
12e41d03
DL
1052}
1053
1054static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1055{
d62a17ae 1056 struct listnode *chnode;
1057 struct listnode *chnextnode;
1058 struct pim_interface *pim_ifp;
1059 struct pim_ifchannel *ch;
1060
1061 /* scan per-interface (S,G) state */
1062 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1063 if (!ch->interface)
1064 continue;
1065 pim_ifp = ch->interface->info;
1066 if (!pim_ifp)
1067 continue;
1068
1069 pim_ifchannel_update_assert_tracking_desired(ch);
1070
1071 } /* scan iface channel list */
12e41d03 1072}
f14248dd 1073
1bf16443 1074/* When kat is stopped CouldRegister goes to false so we need to
1075 * transition the (S, G) on FHR to NI state and remove reg tunnel
1076 * from the OIL */
9b29ea95
DS
1077static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1078 struct pim_upstream *up)
1bf16443 1079{
d62a17ae 1080 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1081 return;
1082
1083 if (PIM_DEBUG_TRACE)
1084 zlog_debug("kat expired on %s; clear fhr reg state",
1085 up->sg_str);
1086
1087 /* stop reg-stop timer */
1088 THREAD_OFF(up->t_rs_timer);
1089 /* remove regiface from the OIL if it is there*/
9b29ea95 1090 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1091 PIM_OIF_FLAG_PROTO_PIM);
1092 /* clear the register state */
1093 up->reg_state = PIM_REG_NOINFO;
1094 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1bf16443 1095}
1096
1097/* When kat is started CouldRegister can go to true. And if it does we
1098 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1099 * to the OIL */
1100static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1101{
d62a17ae 1102 if (pim_upstream_could_register(up)) {
1103 if (PIM_DEBUG_TRACE)
1104 zlog_debug(
1105 "kat started on %s; set fhr reg state to joined",
1106 up->sg_str);
1107
1108 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1109 if (up->reg_state == PIM_REG_NOINFO)
1110 pim_register_join(up);
1111 }
1bf16443 1112}
1113
f14248dd
DS
1114/*
1115 * On an RP, the PMBR value must be cleared when the
1116 * Keepalive Timer expires
1bf16443 1117 * KAT expiry indicates that flow is inactive. If the flow was created or
1118 * maintained by activity now is the time to deref it.
f14248dd 1119 */
d62a17ae 1120static int pim_upstream_keep_alive_timer(struct thread *t)
f14248dd 1121{
d62a17ae 1122 struct pim_upstream *up;
8e5f97e3 1123 struct pim_instance *pim;
d62a17ae 1124
1125 up = THREAD_ARG(t);
8e5f97e3 1126 pim = up->channel_oil->pim;
d62a17ae 1127
8e5f97e3 1128 if (I_am_RP(pim, up->sg.grp)) {
d62a17ae 1129 pim_br_clear_pmbr(&up->sg);
1130 /*
1131 * We need to do more here :)
1132 * But this is the start.
1133 */
1134 }
1135
1136 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1137 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1138
1139 /* if entry was created because of activity we need to deref it */
1140 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
8e5f97e3 1141 pim_upstream_fhr_kat_expiry(pim, up);
d62a17ae 1142 if (PIM_DEBUG_TRACE)
996c9314
LB
1143 zlog_debug(
1144 "kat expired on %s[%s]; remove stream reference",
1145 up->sg_str, pim->vrf->name);
d62a17ae 1146 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
8e5f97e3 1147 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
d62a17ae 1148 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
8022df6a
DS
1149 struct pim_upstream *parent = up->parent;
1150
d62a17ae 1151 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
8e5f97e3 1152 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
8022df6a
DS
1153
1154 if (parent) {
996c9314
LB
1155 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1156 true);
8022df6a 1157 }
d62a17ae 1158 }
1159
1160 return 0;
f14248dd
DS
1161}
1162
d62a17ae 1163void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
f14248dd 1164{
d62a17ae 1165 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1166 if (PIM_DEBUG_TRACE)
1167 zlog_debug("kat start on %s with no stream reference",
1168 up->sg_str);
1169 }
1170 THREAD_OFF(up->t_ka_timer);
36417fcc
DS
1171 thread_add_timer(router->master, pim_upstream_keep_alive_timer, up,
1172 time, &up->t_ka_timer);
d62a17ae 1173
1174 /* any time keepalive is started against a SG we will have to
1175 * re-evaluate our active source database */
1176 pim_msdp_sa_local_update(up);
1bf16443 1177}
1178
1179/* MSDP on RP needs to know if a source is registerable to this RP */
d62a17ae 1180static int pim_upstream_msdp_reg_timer(struct thread *t)
1bf16443 1181{
472ad383
DS
1182 struct pim_upstream *up = THREAD_ARG(t);
1183 struct pim_instance *pim = up->channel_oil->pim;
1bf16443 1184
d62a17ae 1185 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1186 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1187 return 1;
1bf16443 1188}
d62a17ae 1189void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1bf16443 1190{
d62a17ae 1191 THREAD_OFF(up->t_msdp_reg_timer);
36417fcc 1192 thread_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
d62a17ae 1193 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1bf16443 1194
d62a17ae 1195 pim_msdp_sa_local_update(up);
f14248dd 1196}
cb40b272
DS
1197
1198/*
1199 * 4.2.1 Last-Hop Switchover to the SPT
1200 *
1201 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1202 * RP. Once traffic from sources to joined groups arrives at a last-hop
1203 * router, it has the option of switching to receive the traffic on a
1204 * shortest path tree (SPT).
1205 *
1206 * The decision for a router to switch to the SPT is controlled as
1207 * follows:
1208 *
1209 * void
1210 * CheckSwitchToSpt(S,G) {
1211 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1212 * (+) pim_include(S,G) != NULL )
1213 * AND SwitchToSptDesired(S,G) ) {
1214 * # Note: Restarting the KAT will result in the SPT switch
1215 * set KeepaliveTimer(S,G) to Keepalive_Period
1216 * }
1217 * }
1218 *
1219 * SwitchToSptDesired(S,G) is a policy function that is implementation
1220 * defined. An "infinite threshold" policy can be implemented by making
1221 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1222 * first packet" policy can be implemented by making
1223 * SwitchToSptDesired(S,G) return true once a single packet has been
1224 * received for the source and group.
1225 */
8e5f97e3
DS
1226int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
1227 struct prefix_sg *sg)
cb40b272 1228{
8e5f97e3 1229 if (I_am_RP(pim, sg->grp))
d62a17ae 1230 return 1;
a3b58b4a 1231
d62a17ae 1232 return 0;
cb40b272 1233}
d7259eac 1234
d62a17ae 1235int pim_upstream_is_sg_rpt(struct pim_upstream *up)
80d9c3a0 1236{
d62a17ae 1237 struct listnode *chnode;
1238 struct pim_ifchannel *ch;
f21597f0 1239
d62a17ae 1240 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1241 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1242 return 1;
1243 }
e43b8697 1244
d62a17ae 1245 return 0;
80d9c3a0 1246}
3a66b17b
DS
1247/*
1248 * After receiving a packet set SPTbit:
1249 * void
1250 * Update_SPTbit(S,G,iif) {
1251 * if ( iif == RPF_interface(S)
1252 * AND JoinDesired(S,G) == TRUE
1253 * AND ( DirectlyConnected(S) == TRUE
1254 * OR RPF_interface(S) != RPF_interface(RP(G))
1255 * OR inherited_olist(S,G,rpt) == NULL
1256 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1257 * ( RPF'(S,G) != NULL ) )
1258 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1259 * Set SPTbit(S,G) to TRUE
1260 * }
1261 * }
1262 */
d62a17ae 1263void pim_upstream_set_sptbit(struct pim_upstream *up,
1264 struct interface *incoming)
3a66b17b 1265{
d62a17ae 1266 struct pim_upstream *starup = up->parent;
1267
1268 // iif == RPF_interfvace(S)
1269 if (up->rpf.source_nexthop.interface != incoming) {
1270 if (PIM_DEBUG_TRACE)
1271 zlog_debug(
1272 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1273 __PRETTY_FUNCTION__, incoming->name,
1274 up->rpf.source_nexthop.interface->name);
1275 return;
1276 }
1277
1278 // AND JoinDesired(S,G) == TRUE
1279 // FIXME
1280
1281 // DirectlyConnected(S) == TRUE
1282 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1283 up->sg.src)) {
1284 if (PIM_DEBUG_TRACE)
1285 zlog_debug("%s: %s is directly connected to the source",
1286 __PRETTY_FUNCTION__, up->sg_str);
1287 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1288 return;
1289 }
1290
1291 // OR RPF_interface(S) != RPF_interface(RP(G))
1292 if (!starup
1293 || up->rpf.source_nexthop
1294 .interface != starup->rpf.source_nexthop.interface) {
1295 if (PIM_DEBUG_TRACE)
1296 zlog_debug(
1297 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1298 __PRETTY_FUNCTION__, up->sg_str);
1299 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1300 return;
1301 }
1302
1303 // OR inherited_olist(S,G,rpt) == NULL
1304 if (pim_upstream_is_sg_rpt(up)
1305 && pim_upstream_empty_inherited_olist(up)) {
1306 if (PIM_DEBUG_TRACE)
1307 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1308 __PRETTY_FUNCTION__, up->sg_str);
1309 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1310 return;
1311 }
1312
1313 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1314 // ( RPF'(S,G) != NULL ) )
1315 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1316 if (PIM_DEBUG_TRACE)
1317 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1318 __PRETTY_FUNCTION__, up->sg_str);
1319 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1320 return;
1321 }
1322
1323 return;
3a66b17b 1324}
80d9c3a0 1325
d62a17ae 1326const char *pim_upstream_state2str(enum pim_upstream_state join_state)
d7259eac 1327{
d62a17ae 1328 switch (join_state) {
1329 case PIM_UPSTREAM_NOTJOINED:
1330 return "NotJoined";
1331 break;
1332 case PIM_UPSTREAM_JOINED:
1333 return "Joined";
1334 break;
1335 }
1336 return "Unknown";
d7259eac 1337}
627ed2a3 1338
d62a17ae 1339const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
e0e127b0 1340{
d62a17ae 1341 switch (reg_state) {
1342 case PIM_REG_NOINFO:
1343 strcpy(state_str, "RegNoInfo");
1344 break;
1345 case PIM_REG_JOIN:
1346 strcpy(state_str, "RegJoined");
1347 break;
1348 case PIM_REG_JOIN_PENDING:
1349 strcpy(state_str, "RegJoinPend");
1350 break;
1351 case PIM_REG_PRUNE:
1352 strcpy(state_str, "RegPrune");
1353 break;
1354 default:
1355 strcpy(state_str, "RegUnknown");
1356 }
1357 return state_str;
e0e127b0 1358}
1359
d62a17ae 1360static int pim_upstream_register_stop_timer(struct thread *t)
627ed2a3 1361{
d62a17ae 1362 struct pim_interface *pim_ifp;
8e5f97e3 1363 struct pim_instance *pim;
d62a17ae 1364 struct pim_upstream *up;
1365 struct pim_rpf *rpg;
1366 struct ip ip_hdr;
1367 up = THREAD_ARG(t);
8e5f97e3 1368 pim = up->channel_oil->pim;
d62a17ae 1369
1370 if (PIM_DEBUG_TRACE) {
1371 char state_str[PIM_REG_STATE_STR_LEN];
8dbdb215
DS
1372 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1373 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1374 pim_reg_state2str(up->reg_state, state_str));
1375 }
1376
1377 switch (up->reg_state) {
1378 case PIM_REG_JOIN_PENDING:
1379 up->reg_state = PIM_REG_JOIN;
8e5f97e3 1380 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1381 PIM_OIF_FLAG_PROTO_PIM);
1382 break;
1383 case PIM_REG_JOIN:
1384 break;
1385 case PIM_REG_PRUNE:
957d93ea
SP
1386 if (!up->rpf.source_nexthop.interface) {
1387 if (PIM_DEBUG_TRACE)
1388 zlog_debug("%s: up %s RPF is not present",
1389 __PRETTY_FUNCTION__, up->sg_str);
1390 return 0;
1391 }
1392
d62a17ae 1393 pim_ifp = up->rpf.source_nexthop.interface->info;
1394 if (!pim_ifp) {
1395 if (PIM_DEBUG_TRACE)
1396 zlog_debug(
1397 "%s: Interface: %s is not configured for pim",
1398 __PRETTY_FUNCTION__,
1399 up->rpf.source_nexthop.interface->name);
1400 return 0;
1401 }
1402 up->reg_state = PIM_REG_JOIN_PENDING;
1403 pim_upstream_start_register_stop_timer(up, 1);
1404
1405 if (((up->channel_oil->cc.lastused / 100)
2f5b0028 1406 > pim->keep_alive_time)
d9c9a9ee 1407 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
d62a17ae 1408 if (PIM_DEBUG_TRACE)
1409 zlog_debug(
1410 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1411 __PRETTY_FUNCTION__);
1412 return 0;
1413 }
d9c9a9ee 1414 rpg = RP(pim_ifp->pim, up->sg.grp);
1e7a3a2a
DS
1415 if (!rpg) {
1416 if (PIM_DEBUG_TRACE)
1417 zlog_debug(
1418 "%s: Cannot send register for %s no RPF to the RP",
1419 __PRETTY_FUNCTION__, up->sg_str);
1420 return 0;
1421 }
d62a17ae 1422 memset(&ip_hdr, 0, sizeof(struct ip));
1423 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1424 ip_hdr.ip_hl = 5;
1425 ip_hdr.ip_v = 4;
1426 ip_hdr.ip_src = up->sg.src;
1427 ip_hdr.ip_dst = up->sg.grp;
1428 ip_hdr.ip_len = htons(20);
1429 // checksum is broken
1430 pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
1431 pim_ifp->primary_address, rpg, 1, up);
1432 break;
1433 default:
1434 break;
70e7fda8 1435 }
d62a17ae 1436
1437 return 0;
627ed2a3
DS
1438}
1439
d62a17ae 1440void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1441 int null_register)
627ed2a3 1442{
d62a17ae 1443 uint32_t time;
1444
1445 THREAD_TIMER_OFF(up->t_rs_timer);
1446
1447 if (!null_register) {
1448 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1449 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1450 time = lower + (random() % (upper - lower + 1))
1451 - PIM_REGISTER_PROBE_PERIOD;
1452 } else
1453 time = PIM_REGISTER_PROBE_PERIOD;
1454
1455 if (PIM_DEBUG_TRACE) {
1456 zlog_debug(
1457 "%s: (S,G)=%s Starting upstream register stop timer %d",
1458 __PRETTY_FUNCTION__, up->sg_str, time);
1459 }
36417fcc
DS
1460 thread_add_timer(router->master, pim_upstream_register_stop_timer, up,
1461 time, &up->t_rs_timer);
627ed2a3 1462}
4fdc8f36 1463
9b29ea95
DS
1464int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1465 struct pim_upstream *up)
4fdc8f36 1466{
d62a17ae 1467 struct interface *ifp;
1468 struct pim_interface *pim_ifp = NULL;
1469 struct pim_ifchannel *ch, *starch;
d62a17ae 1470 struct pim_upstream *starup = up->parent;
1471 int output_intf = 0;
1472
1473 if (up->rpf.source_nexthop.interface)
1474 pim_ifp = up->rpf.source_nexthop.interface->info;
1475 else {
1476 if (PIM_DEBUG_TRACE)
1477 zlog_debug("%s: up %s RPF is not present",
1478 __PRETTY_FUNCTION__, up->sg_str);
1479 }
1480 if (pim_ifp && !up->channel_oil)
611925dc
DS
1481 up->channel_oil = pim_channel_oil_add(
1482 pim, &up->sg, pim_ifp->mroute_vif_index);
d62a17ae 1483
451fda4f 1484 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1485 if (!ifp->info)
1486 continue;
1487
1488 ch = pim_ifchannel_find(ifp, &up->sg);
1489
1490 if (starup)
1491 starch = pim_ifchannel_find(ifp, &starup->sg);
1492 else
1493 starch = NULL;
1494
1495 if (!ch && !starch)
1496 continue;
1497
1498 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1499 starch)) {
1500 int flag = PIM_OIF_FLAG_PROTO_PIM;
1501
1502 if (!ch)
1503 flag = PIM_OIF_FLAG_PROTO_STAR;
1504
1505 pim_channel_add_oif(up->channel_oil, ifp, flag);
1506 output_intf++;
1507 }
1508 }
1509
1510 return output_intf;
b5183fd1
DS
1511}
1512
1513/*
1514 * For a given upstream, determine the inherited_olist
1515 * and apply it.
1516 *
1517 * inherited_olist(S,G,rpt) =
1518 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1519 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1520 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1521 *
1522 * inherited_olist(S,G) =
1523 * inherited_olist(S,G,rpt) (+)
1524 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1525 *
1526 * return 1 if there are any output interfaces
1527 * return 0 if there are not any output interfaces
1528 */
9b29ea95
DS
1529int pim_upstream_inherited_olist(struct pim_instance *pim,
1530 struct pim_upstream *up)
b5183fd1 1531{
9b29ea95 1532 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1533
1534 /*
1535 * If we have output_intf switch state to Join and work like normal
1536 * If we don't have an output_intf that means we are probably a
1537 * switch on a stick so turn on forwarding to just accept the
1538 * incoming packets so we don't bother the other stuff!
1539 */
1540 if (output_intf)
1eca8576 1541 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 1542 else
1543 forward_on(up);
1544
1545 return output_intf;
4fdc8f36 1546}
d3dd1804 1547
d62a17ae 1548int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
80d9c3a0 1549{
d62a17ae 1550 return pim_channel_oil_empty(up->channel_oil);
80d9c3a0
DS
1551}
1552
d3dd1804
DS
1553/*
1554 * When we have a new neighbor,
1555 * find upstreams that don't have their rpf_addr
1556 * set and see if the new neighbor allows
1557 * the join to be sent
1558 */
9b29ea95 1559void pim_upstream_find_new_rpf(struct pim_instance *pim)
d3dd1804 1560{
d62a17ae 1561 struct listnode *up_node;
1562 struct listnode *up_nextnode;
1563 struct pim_upstream *up;
1564
1565 /*
1566 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1567 */
9b29ea95 1568 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
957d93ea
SP
1569 if (up->upstream_addr.s_addr == INADDR_ANY) {
1570 if (PIM_DEBUG_TRACE)
1571 zlog_debug(
1572 "%s: RP not configured for Upstream %s",
1573 __PRETTY_FUNCTION__, up->sg_str);
1574 continue;
1575 }
1576
d62a17ae 1577 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1578 if (PIM_DEBUG_TRACE)
1579 zlog_debug(
957d93ea
SP
1580 "%s: Upstream %s without a path to send join, checking",
1581 __PRETTY_FUNCTION__, up->sg_str);
2002dcdb 1582 pim_rpf_update(pim, up, NULL, 1);
d62a17ae 1583 }
d3dd1804 1584 }
d3dd1804 1585}
0f588989 1586
7c591950 1587unsigned int pim_upstream_hash_key(void *arg)
0f588989 1588{
d62a17ae 1589 struct pim_upstream *up = (struct pim_upstream *)arg;
0f588989 1590
d62a17ae 1591 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
0f588989
DS
1592}
1593
9b29ea95 1594void pim_upstream_terminate(struct pim_instance *pim)
0f588989 1595{
172e45dc
DS
1596 struct pim_upstream *up;
1597
1598 if (pim->upstream_list) {
1d483838
DS
1599 while (pim->upstream_list->count) {
1600 up = listnode_head(pim->upstream_list);
172e45dc 1601 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1d483838 1602 }
172e45dc 1603
6a154c88 1604 list_delete(&pim->upstream_list);
172e45dc 1605 }
0f588989 1606
9b29ea95
DS
1607 if (pim->upstream_hash)
1608 hash_free(pim->upstream_hash);
1609 pim->upstream_hash = NULL;
0c68972d
DS
1610
1611 if (pim->upstream_sg_wheel)
1612 wheel_delete(pim->upstream_sg_wheel);
1613 pim->upstream_sg_wheel = NULL;
0f588989
DS
1614}
1615
74df8d6d 1616bool pim_upstream_equal(const void *arg1, const void *arg2)
0f588989 1617{
d62a17ae 1618 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1619 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
0f588989 1620
d62a17ae 1621 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1622 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
74df8d6d 1623 return true;
0f588989 1624
74df8d6d 1625 return false;
0f588989
DS
1626}
1627
1bf16443 1628/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1629 * the cases where kat has to be restarted on rxing traffic -
1630 *
1631 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1632 * set KeepaliveTimer(S,G) to Keepalive_Period
1633 * # Note: a register state transition or UpstreamJPState(S,G)
1634 * # transition may happen as a result of restarting
1635 * # KeepaliveTimer, and must be dealt with here.
1636 * }
1637 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1638 * inherited_olist(S,G) != NULL ) {
1639 * set KeepaliveTimer(S,G) to Keepalive_Period
1640 * }
1641 */
1642static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1643{
8e5f97e3
DS
1644 struct pim_instance *pim = up->channel_oil->pim;
1645
d62a17ae 1646 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1647 * so we will skip that here */
957d93ea
SP
1648 if (up->rpf.source_nexthop.interface &&
1649 pim_if_connected_to_source(up->rpf.source_nexthop.interface,
d62a17ae 1650 up->sg.src)) {
1651 return true;
1652 }
1653
1654 if ((up->join_state == PIM_UPSTREAM_JOINED)
1655 && !pim_upstream_empty_inherited_olist(up)) {
1656 /* XXX: I have added this RP check just for 3.2 and it's a
1657 * digression from
1658 * what rfc-4601 says. Till now we were only running KAT on FHR
1659 * and RP and
1660 * there is some angst around making the change to run it all
1661 * routers that
1662 * maintain the (S, G) state. This is tracked via CM-13601 and
1663 * MUST be
1664 * removed to handle spt turn-arounds correctly in a 3-tier clos
1665 */
8e5f97e3 1666 if (I_am_RP(pim, up->sg.grp))
d62a17ae 1667 return true;
1668 }
1669
1670 return false;
1bf16443 1671}
1672
9c5e4d62
DS
1673/*
1674 * Code to check and see if we've received packets on a S,G mroute
1675 * and if so to set the SPT bit appropriately
1676 */
d62a17ae 1677static void pim_upstream_sg_running(void *arg)
9c5e4d62 1678{
d62a17ae 1679 struct pim_upstream *up = (struct pim_upstream *)arg;
8e5f97e3 1680 struct pim_instance *pim = up->channel_oil->pim;
d62a17ae 1681
1682 // No packet can have arrived here if this is the case
8e5f97e3 1683 if (!up->channel_oil->installed) {
d62a17ae 1684 if (PIM_DEBUG_TRACE)
6c65db5f 1685 zlog_debug("%s: %s[%s] is not installed in mroute",
996c9314
LB
1686 __PRETTY_FUNCTION__, up->sg_str,
1687 pim->vrf->name);
d62a17ae 1688 return;
1689 }
1690
1691 /*
1692 * This is a bit of a hack
1693 * We've noted that we should rescan but
1694 * we've missed the window for doing so in
1695 * pim_zebra.c for some reason. I am
1696 * only doing this at this point in time
1697 * to get us up and working for the moment
1698 */
1699 if (up->channel_oil->oil_inherited_rescan) {
1700 if (PIM_DEBUG_TRACE)
1701 zlog_debug(
8dbdb215 1702 "%s: Handling unscanned inherited_olist for %s[%s]",
996c9314
LB
1703 __PRETTY_FUNCTION__, up->sg_str,
1704 pim->vrf->name);
8e5f97e3 1705 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1706 up->channel_oil->oil_inherited_rescan = 0;
1707 }
1708 pim_mroute_update_counters(up->channel_oil);
1709
1710 // Have we seen packets?
1711 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1712 && (up->channel_oil->cc.lastused / 100 > 30)) {
1713 if (PIM_DEBUG_TRACE) {
1714 zlog_debug(
8dbdb215
DS
1715 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1716 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1717 up->channel_oil->cc.oldpktcnt,
1718 up->channel_oil->cc.pktcnt,
1719 up->channel_oil->cc.lastused / 100);
1720 }
1721 return;
e43b8697 1722 }
d62a17ae 1723
1724 if (pim_upstream_kat_start_ok(up)) {
1725 /* Add a source reference to the stream if
1726 * one doesn't already exist */
1727 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1728 if (PIM_DEBUG_TRACE)
1729 zlog_debug(
8dbdb215
DS
1730 "source reference created on kat restart %s[%s]",
1731 up->sg_str, pim->vrf->name);
d62a17ae 1732
1733 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1734 __PRETTY_FUNCTION__);
1735 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1736 pim_upstream_fhr_kat_start(up);
1737 }
19b807ca 1738 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1739 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
19b807ca 1740 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1741
957d93ea
SP
1742 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
1743 (up->rpf.source_nexthop.interface)) {
d62a17ae 1744 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
850a9f99 1745 }
d62a17ae 1746 return;
9c5e4d62
DS
1747}
1748
9b29ea95 1749void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
a7b2b1e2 1750{
d62a17ae 1751 struct pim_upstream *up;
1752 struct listnode *node;
a7b2b1e2 1753
9b29ea95 1754 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1755 if (up->sg.src.s_addr != INADDR_ANY)
1756 continue;
a7b2b1e2 1757
d62a17ae 1758 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1759 continue;
a7b2b1e2 1760
9b29ea95 1761 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1762 PIM_OIF_FLAG_PROTO_IGMP);
1763 }
a7b2b1e2
DS
1764}
1765
9b29ea95
DS
1766void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
1767 struct prefix_list *pl)
df94f9a9 1768{
d62a17ae 1769 const char *pname = prefix_list_name(pl);
df94f9a9 1770
9b29ea95
DS
1771 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
1772 pim_upstream_remove_lhr_star_pimreg(pim, pname);
d62a17ae 1773 }
df94f9a9
DS
1774}
1775
1776/*
1777 * nlist -> The new prefix list
1778 *
1779 * Per Group Application of pimreg to the OIL
1780 * If the prefix list tells us DENY then
1781 * we need to Switchover to SPT immediate
1782 * so add the pimreg.
1783 * If the prefix list tells us to ACCEPT than
1784 * we need to Never do the SPT so remove
1785 * the interface
1786 *
1787 */
9b29ea95
DS
1788void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
1789 const char *nlist)
a7b2b1e2 1790{
d62a17ae 1791 struct pim_upstream *up;
1792 struct listnode *node;
1793 struct prefix_list *np;
1794 struct prefix g;
1795 enum prefix_list_type apply_new;
1796
1797 np = prefix_list_lookup(AFI_IP, nlist);
1798
1799 g.family = AF_INET;
1800 g.prefixlen = IPV4_MAX_PREFIXLEN;
1801
9b29ea95 1802 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1803 if (up->sg.src.s_addr != INADDR_ANY)
1804 continue;
1805
1806 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1807 continue;
1808
1809 if (!nlist) {
9b29ea95 1810 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1811 PIM_OIF_FLAG_PROTO_IGMP);
1812 continue;
1813 }
1814 g.u.prefix4 = up->sg.grp;
1815 apply_new = prefix_list_apply(np, &g);
1816 if (apply_new == PREFIX_DENY)
9b29ea95 1817 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1818 PIM_OIF_FLAG_PROTO_IGMP);
1819 else
9b29ea95 1820 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1821 PIM_OIF_FLAG_PROTO_IGMP);
1822 }
a7b2b1e2
DS
1823}
1824
9b29ea95 1825void pim_upstream_init(struct pim_instance *pim)
0f588989 1826{
c2cfa843 1827 char name[64];
9fb302f4 1828
c2cfa843
DS
1829 snprintf(name, 64, "PIM %s Timer Wheel",
1830 pim->vrf->name);
9b29ea95 1831 pim->upstream_sg_wheel =
36417fcc 1832 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
c2cfa843 1833 pim_upstream_sg_running, name);
9fb302f4 1834
c2cfa843
DS
1835 snprintf(name, 64, "PIM %s Upstream Hash",
1836 pim->vrf->name);
9b29ea95 1837 pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
c2cfa843 1838 pim_upstream_equal, name);
d62a17ae 1839
9b29ea95 1840 pim->upstream_list = list_new();
9b29ea95 1841 pim->upstream_list->cmp = pim_upstream_compare;
0f588989 1842}