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