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