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