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