]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
Merge pull request #2574 from pacovn/Coverity_1399202_Copy-paste_error
[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));
606 if (!up) {
607 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
608 sizeof(*up));
609 return NULL;
610 }
611
612 up->sg = *sg;
613 pim_str_sg_set(sg, up->sg_str);
0885a9f1
DS
614 if (ch)
615 ch->upstream = up;
616
9b29ea95 617 up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
d9c9a9ee
DS
618 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
619 sg->grp)) {
d62a17ae 620 if (PIM_DEBUG_TRACE)
621 zlog_debug("%s: Received a (*,G) with no RP configured",
622 __PRETTY_FUNCTION__);
623
9b29ea95 624 hash_release(pim->upstream_hash, up);
d62a17ae 625 XFREE(MTYPE_PIM_UPSTREAM, up);
626 return NULL;
627 }
628
9b29ea95 629 up->parent = pim_upstream_find_parent(pim, up);
d62a17ae 630 if (up->sg.src.s_addr == INADDR_ANY) {
631 up->sources = list_new();
632 up->sources->cmp = pim_upstream_compare;
633 } else
634 up->sources = NULL;
635
9b29ea95 636 pim_upstream_find_new_children(pim, up);
d62a17ae 637 up->flags = flags;
638 up->ref_count = 1;
639 up->t_join_timer = NULL;
640 up->t_ka_timer = NULL;
641 up->t_rs_timer = NULL;
642 up->t_msdp_reg_timer = NULL;
643 up->join_state = PIM_UPSTREAM_NOTJOINED;
644 up->reg_state = PIM_REG_NOINFO;
645 up->state_transition = pim_time_monotonic_sec();
646 up->channel_oil = NULL;
647 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
648
649 up->rpf.source_nexthop.interface = NULL;
650 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
651 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
652 PIM_NET_INADDR_ANY;
653 up->rpf.source_nexthop.mrib_metric_preference =
654 qpim_infinite_assert_metric.metric_preference;
655 up->rpf.source_nexthop.mrib_route_metric =
656 qpim_infinite_assert_metric.route_metric;
657 up->rpf.rpf_addr.family = AF_INET;
658 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
659
660 up->ifchannels = list_new();
661 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
662
663 if (up->sg.src.s_addr != INADDR_ANY)
9b29ea95 664 wheel_add_item(pim->upstream_sg_wheel, up);
d62a17ae 665
2002dcdb 666 rpf_result = pim_rpf_update(pim, up, NULL, 1);
d62a17ae 667 if (rpf_result == PIM_RPF_FAILURE) {
668 struct prefix nht_p;
669
670 if (PIM_DEBUG_TRACE)
671 zlog_debug(
672 "%s: Attempting to create upstream(%s), Unable to RPF for source",
673 __PRETTY_FUNCTION__, up->sg_str);
674
675 nht_p.family = AF_INET;
676 nht_p.prefixlen = IPV4_MAX_BITLEN;
677 nht_p.u.prefix4 = up->upstream_addr;
2002dcdb 678 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
d62a17ae 679
680 if (up->parent) {
681 listnode_delete(up->parent->sources, up);
682 up->parent = NULL;
683 }
684
685 if (up->sg.src.s_addr != INADDR_ANY)
9b29ea95 686 wheel_remove_item(pim->upstream_sg_wheel, up);
d62a17ae 687
9b29ea95 688 pim_upstream_remove_children(pim, up);
d62a17ae 689 if (up->sources)
affe9e99 690 list_delete_and_null(&up->sources);
d62a17ae 691
affe9e99 692 list_delete_and_null(&up->ifchannels);
a5d4c69d 693
9b29ea95 694 hash_release(pim->upstream_hash, up);
d62a17ae 695 XFREE(MTYPE_PIM_UPSTREAM, up);
696 return NULL;
697 }
698
699 if (up->rpf.source_nexthop.interface) {
700 pim_ifp = up->rpf.source_nexthop.interface->info;
701 if (pim_ifp)
702 up->channel_oil = pim_channel_oil_add(
611925dc 703 pim, &up->sg, pim_ifp->mroute_vif_index);
d62a17ae 704 }
9b29ea95 705 listnode_add_sort(pim->upstream_list, up);
d62a17ae 706
707 if (PIM_DEBUG_TRACE) {
708 zlog_debug(
709 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
710 __PRETTY_FUNCTION__, up->sg_str,
711 inet_ntoa(up->upstream_addr), up->ref_count);
712 }
713
714 return up;
12e41d03
DL
715}
716
9b29ea95
DS
717struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
718 struct prefix_sg *sg)
12e41d03 719{
d62a17ae 720 struct pim_upstream lookup;
721 struct pim_upstream *up = NULL;
12e41d03 722
d62a17ae 723 lookup.sg = *sg;
9b29ea95 724 up = hash_lookup(pim->upstream_hash, &lookup);
d62a17ae 725 return up;
12e41d03
DL
726}
727
d62a17ae 728struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
729 struct interface *incoming,
730 int flags, const char *name)
e711cd3c 731{
d62a17ae 732 struct pim_upstream *up;
9b29ea95
DS
733 struct pim_interface *pim_ifp;
734
735 pim_ifp = incoming->info;
d62a17ae 736
9b29ea95 737 up = pim_upstream_find(pim_ifp->pim, sg);
d62a17ae 738
739 if (up) {
740 if (!(up->flags & flags)) {
741 up->flags |= flags;
742 up->ref_count++;
743 if (PIM_DEBUG_TRACE)
744 zlog_debug(
745 "%s(%s): upstream %s ref count %d increment",
746 __PRETTY_FUNCTION__, name, up->sg_str,
747 up->ref_count);
748 }
749 } else
0885a9f1
DS
750 up = pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
751 NULL);
d62a17ae 752
753 return up;
e711cd3c
DS
754}
755
d62a17ae 756void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1bf16443 757{
d62a17ae 758 up->flags |= flags;
759 ++up->ref_count;
760 if (PIM_DEBUG_TRACE)
761 zlog_debug("%s(%s): upstream %s ref count %d increment",
762 __PRETTY_FUNCTION__, name, up->sg_str,
763 up->ref_count);
1bf16443 764}
765
2002dcdb
DS
766struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
767 struct prefix_sg *sg,
d62a17ae 768 struct interface *incoming, int flags,
0885a9f1
DS
769 const char *name,
770 struct pim_ifchannel *ch)
12e41d03 771{
d62a17ae 772 struct pim_upstream *up = NULL;
773 int found = 0;
9b29ea95 774
2002dcdb 775 up = pim_upstream_find(pim, sg);
d62a17ae 776 if (up) {
777 pim_upstream_ref(up, flags, name);
778 found = 1;
779 } else {
0885a9f1 780 up = pim_upstream_new(pim, sg, incoming, flags, ch);
d62a17ae 781 }
782
783 if (PIM_DEBUG_TRACE) {
784 if (up) {
785 char buf[PREFIX2STR_BUFFER];
786 prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf));
787 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
f4075cb4 788 __PRETTY_FUNCTION__, name,
55785900
CS
789 up->sg_str, buf, up->rpf.source_nexthop.interface ?
790 up->rpf.source_nexthop.interface->name : "NIL" ,
791 found, up->ref_count);
d62a17ae 792 } else
793 zlog_debug("%s(%s): (%s) failure to create",
794 __PRETTY_FUNCTION__, name,
795 pim_str_sg_dump(sg));
796 }
12e41d03 797
d62a17ae 798 return up;
12e41d03
DL
799}
800
c8fc07cb
DS
801/*
802 * Passed in up must be the upstream for ch. starch is NULL if no
803 * information
804 */
d62a17ae 805int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
806 struct pim_ifchannel *ch,
807 struct pim_ifchannel *starch)
7a3ddda5 808{
d62a17ae 809 if (ch) {
810 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
811 return 0;
812
813 if (!pim_macro_ch_lost_assert(ch)
814 && pim_macro_chisin_joins_or_include(ch))
815 return 1;
816 }
817
818 /*
819 * joins (*,G)
820 */
821 if (starch) {
822 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
823 return 0;
824
825 if (!pim_macro_ch_lost_assert(starch)
826 && pim_macro_chisin_joins_or_include(starch))
827 return 1;
828 }
829
830 return 0;
7a3ddda5
DS
831}
832
12e41d03
DL
833/*
834 Evaluate JoinDesired(S,G):
835
836 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
837 in the set:
838
839 inherited_olist(S,G) =
840 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
841
842 JoinDesired(S,G) may be affected by changes in the following:
843
844 pim_ifp->primary_address
845 pim_ifp->pim_dr_addr
846 ch->ifassert_winner_metric
847 ch->ifassert_winner
d62a17ae 848 ch->local_ifmembership
12e41d03
DL
849 ch->ifjoin_state
850 ch->upstream->rpf.source_nexthop.mrib_metric_preference
851 ch->upstream->rpf.source_nexthop.mrib_route_metric
852 ch->upstream->rpf.source_nexthop.interface
853
854 See also pim_upstream_update_join_desired() below.
855 */
9b29ea95
DS
856int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
857 struct pim_upstream *up)
12e41d03 858{
d62a17ae 859 struct interface *ifp;
d62a17ae 860 struct pim_ifchannel *ch, *starch;
861 struct pim_upstream *starup = up->parent;
862 int ret = 0;
12e41d03 863
451fda4f 864 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 865 if (!ifp->info)
866 continue;
c8fc07cb 867
d62a17ae 868 ch = pim_ifchannel_find(ifp, &up->sg);
c8fc07cb 869
d62a17ae 870 if (starup)
871 starch = pim_ifchannel_find(ifp, &starup->sg);
872 else
873 starch = NULL;
c8fc07cb 874
d62a17ae 875 if (!ch && !starch)
876 continue;
12e41d03 877
d62a17ae 878 ret += pim_upstream_evaluate_join_desired_interface(up, ch,
879 starch);
880 } /* scan iface channel list */
12e41d03 881
d62a17ae 882 return ret; /* false */
12e41d03
DL
883}
884
885/*
886 See also pim_upstream_evaluate_join_desired() above.
887*/
9b29ea95
DS
888void pim_upstream_update_join_desired(struct pim_instance *pim,
889 struct pim_upstream *up)
12e41d03 890{
d62a17ae 891 int was_join_desired; /* boolean */
892 int is_join_desired; /* boolean */
893
894 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
895
9b29ea95 896 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
d62a17ae 897 if (is_join_desired)
898 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
899 else
900 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
901
902 /* switched from false to true */
903 if (is_join_desired && !was_join_desired) {
1eca8576 904 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 905 return;
906 }
907
908 /* switched from true to false */
909 if (!is_join_desired && was_join_desired) {
1eca8576 910 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
d62a17ae 911 return;
912 }
12e41d03
DL
913}
914
915/*
916 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
917 Transitions from Joined State
918 RPF'(S,G) GenID changes
919
920 The upstream (S,G) state machine remains in Joined state. If the
921 Join Timer is set to expire in more than t_override seconds, reset
922 it so that it expires after t_override seconds.
923*/
9b29ea95
DS
924void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
925 struct in_addr neigh_addr)
12e41d03 926{
d62a17ae 927 struct listnode *up_node;
928 struct listnode *up_nextnode;
929 struct pim_upstream *up;
930
931 /*
932 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
933 */
9b29ea95 934 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
d62a17ae 935
936 if (PIM_DEBUG_TRACE) {
937 char neigh_str[INET_ADDRSTRLEN];
938 char rpf_addr_str[PREFIX_STRLEN];
939 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
940 sizeof(neigh_str));
941 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
942 sizeof(rpf_addr_str));
943 zlog_debug(
8dbdb215 944 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
996c9314
LB
945 __PRETTY_FUNCTION__, neigh_str, up->sg_str,
946 pim->vrf->name,
d62a17ae 947 up->join_state == PIM_UPSTREAM_JOINED,
948 rpf_addr_str);
949 }
950
951 /* consider only (S,G) upstream in Joined state */
952 if (up->join_state != PIM_UPSTREAM_JOINED)
953 continue;
954
955 /* match RPF'(S,G)=neigh_addr */
956 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
957 continue;
958
959 pim_upstream_join_timer_decrease_to_t_override(
960 "RPF'(S,G) GenID change", up);
961 }
12e41d03
DL
962}
963
964
965void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
966 struct interface *old_rpf_ifp)
967{
d62a17ae 968 struct listnode *chnode;
969 struct listnode *chnextnode;
970 struct pim_ifchannel *ch;
971
972 /* search all ifchannels */
973 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
974 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
975 if (
976 /* RPF_interface(S) was NOT I */
977 (old_rpf_ifp == ch->interface) &&
978 /* RPF_interface(S) stopped being I */
979 (ch->upstream->rpf.source_nexthop
980 .interface != ch->interface)) {
981 assert_action_a5(ch);
982 }
983 } /* PIM_IFASSERT_I_AM_LOSER */
984
985 pim_ifchannel_update_assert_tracking_desired(ch);
986 }
12e41d03
DL
987}
988
989void pim_upstream_update_could_assert(struct pim_upstream *up)
990{
d62a17ae 991 struct listnode *chnode;
992 struct listnode *chnextnode;
993 struct pim_ifchannel *ch;
994
995 /* scan per-interface (S,G) state */
996 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
997 pim_ifchannel_update_could_assert(ch);
998 } /* scan iface channel list */
12e41d03
DL
999}
1000
1001void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1002{
d62a17ae 1003 struct listnode *chnode;
1004 struct listnode *chnextnode;
1005 struct pim_ifchannel *ch;
12e41d03 1006
d62a17ae 1007 /* scan per-interface (S,G) state */
1008 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1009 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 1010
d62a17ae 1011 } /* scan iface channel list */
12e41d03
DL
1012}
1013
1014static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1015{
d62a17ae 1016 struct listnode *chnode;
1017 struct listnode *chnextnode;
1018 struct pim_interface *pim_ifp;
1019 struct pim_ifchannel *ch;
1020
1021 /* scan per-interface (S,G) state */
1022 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1023 if (!ch->interface)
1024 continue;
1025 pim_ifp = ch->interface->info;
1026 if (!pim_ifp)
1027 continue;
1028
1029 pim_ifchannel_update_assert_tracking_desired(ch);
1030
1031 } /* scan iface channel list */
12e41d03 1032}
f14248dd 1033
1bf16443 1034/* When kat is stopped CouldRegister goes to false so we need to
1035 * transition the (S, G) on FHR to NI state and remove reg tunnel
1036 * from the OIL */
9b29ea95
DS
1037static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1038 struct pim_upstream *up)
1bf16443 1039{
d62a17ae 1040 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1041 return;
1042
1043 if (PIM_DEBUG_TRACE)
1044 zlog_debug("kat expired on %s; clear fhr reg state",
1045 up->sg_str);
1046
1047 /* stop reg-stop timer */
1048 THREAD_OFF(up->t_rs_timer);
1049 /* remove regiface from the OIL if it is there*/
9b29ea95 1050 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1051 PIM_OIF_FLAG_PROTO_PIM);
1052 /* clear the register state */
1053 up->reg_state = PIM_REG_NOINFO;
1054 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1bf16443 1055}
1056
1057/* When kat is started CouldRegister can go to true. And if it does we
1058 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1059 * to the OIL */
1060static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1061{
d62a17ae 1062 if (pim_upstream_could_register(up)) {
1063 if (PIM_DEBUG_TRACE)
1064 zlog_debug(
1065 "kat started on %s; set fhr reg state to joined",
1066 up->sg_str);
1067
1068 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1069 if (up->reg_state == PIM_REG_NOINFO)
1070 pim_register_join(up);
1071 }
1bf16443 1072}
1073
f14248dd
DS
1074/*
1075 * On an RP, the PMBR value must be cleared when the
1076 * Keepalive Timer expires
1bf16443 1077 * KAT expiry indicates that flow is inactive. If the flow was created or
1078 * maintained by activity now is the time to deref it.
f14248dd 1079 */
d62a17ae 1080static int pim_upstream_keep_alive_timer(struct thread *t)
f14248dd 1081{
d62a17ae 1082 struct pim_upstream *up;
8e5f97e3 1083 struct pim_instance *pim;
d62a17ae 1084
1085 up = THREAD_ARG(t);
8e5f97e3 1086 pim = up->channel_oil->pim;
d62a17ae 1087
8e5f97e3 1088 if (I_am_RP(pim, up->sg.grp)) {
d62a17ae 1089 pim_br_clear_pmbr(&up->sg);
1090 /*
1091 * We need to do more here :)
1092 * But this is the start.
1093 */
1094 }
1095
1096 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1097 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1098
1099 /* if entry was created because of activity we need to deref it */
1100 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
8e5f97e3 1101 pim_upstream_fhr_kat_expiry(pim, up);
d62a17ae 1102 if (PIM_DEBUG_TRACE)
996c9314
LB
1103 zlog_debug(
1104 "kat expired on %s[%s]; remove stream reference",
1105 up->sg_str, pim->vrf->name);
d62a17ae 1106 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
8e5f97e3 1107 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
d62a17ae 1108 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
8022df6a
DS
1109 struct pim_upstream *parent = up->parent;
1110
d62a17ae 1111 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
8e5f97e3 1112 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
8022df6a
DS
1113
1114 if (parent) {
996c9314
LB
1115 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1116 true);
8022df6a 1117 }
d62a17ae 1118 }
1119
1120 return 0;
f14248dd
DS
1121}
1122
d62a17ae 1123void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
f14248dd 1124{
d62a17ae 1125 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1126 if (PIM_DEBUG_TRACE)
1127 zlog_debug("kat start on %s with no stream reference",
1128 up->sg_str);
1129 }
1130 THREAD_OFF(up->t_ka_timer);
1131 thread_add_timer(master, pim_upstream_keep_alive_timer, up, time,
1132 &up->t_ka_timer);
1133
1134 /* any time keepalive is started against a SG we will have to
1135 * re-evaluate our active source database */
1136 pim_msdp_sa_local_update(up);
1bf16443 1137}
1138
1139/* MSDP on RP needs to know if a source is registerable to this RP */
d62a17ae 1140static int pim_upstream_msdp_reg_timer(struct thread *t)
1bf16443 1141{
472ad383
DS
1142 struct pim_upstream *up = THREAD_ARG(t);
1143 struct pim_instance *pim = up->channel_oil->pim;
1bf16443 1144
d62a17ae 1145 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1146 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1147 return 1;
1bf16443 1148}
d62a17ae 1149void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1bf16443 1150{
d62a17ae 1151 THREAD_OFF(up->t_msdp_reg_timer);
1152 thread_add_timer(master, pim_upstream_msdp_reg_timer, up,
1153 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1bf16443 1154
d62a17ae 1155 pim_msdp_sa_local_update(up);
f14248dd 1156}
cb40b272
DS
1157
1158/*
1159 * 4.2.1 Last-Hop Switchover to the SPT
1160 *
1161 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1162 * RP. Once traffic from sources to joined groups arrives at a last-hop
1163 * router, it has the option of switching to receive the traffic on a
1164 * shortest path tree (SPT).
1165 *
1166 * The decision for a router to switch to the SPT is controlled as
1167 * follows:
1168 *
1169 * void
1170 * CheckSwitchToSpt(S,G) {
1171 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1172 * (+) pim_include(S,G) != NULL )
1173 * AND SwitchToSptDesired(S,G) ) {
1174 * # Note: Restarting the KAT will result in the SPT switch
1175 * set KeepaliveTimer(S,G) to Keepalive_Period
1176 * }
1177 * }
1178 *
1179 * SwitchToSptDesired(S,G) is a policy function that is implementation
1180 * defined. An "infinite threshold" policy can be implemented by making
1181 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1182 * first packet" policy can be implemented by making
1183 * SwitchToSptDesired(S,G) return true once a single packet has been
1184 * received for the source and group.
1185 */
8e5f97e3
DS
1186int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
1187 struct prefix_sg *sg)
cb40b272 1188{
8e5f97e3 1189 if (I_am_RP(pim, sg->grp))
d62a17ae 1190 return 1;
a3b58b4a 1191
d62a17ae 1192 return 0;
cb40b272 1193}
d7259eac 1194
d62a17ae 1195int pim_upstream_is_sg_rpt(struct pim_upstream *up)
80d9c3a0 1196{
d62a17ae 1197 struct listnode *chnode;
1198 struct pim_ifchannel *ch;
f21597f0 1199
d62a17ae 1200 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1201 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1202 return 1;
1203 }
e43b8697 1204
d62a17ae 1205 return 0;
80d9c3a0 1206}
3a66b17b
DS
1207/*
1208 * After receiving a packet set SPTbit:
1209 * void
1210 * Update_SPTbit(S,G,iif) {
1211 * if ( iif == RPF_interface(S)
1212 * AND JoinDesired(S,G) == TRUE
1213 * AND ( DirectlyConnected(S) == TRUE
1214 * OR RPF_interface(S) != RPF_interface(RP(G))
1215 * OR inherited_olist(S,G,rpt) == NULL
1216 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1217 * ( RPF'(S,G) != NULL ) )
1218 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1219 * Set SPTbit(S,G) to TRUE
1220 * }
1221 * }
1222 */
d62a17ae 1223void pim_upstream_set_sptbit(struct pim_upstream *up,
1224 struct interface *incoming)
3a66b17b 1225{
d62a17ae 1226 struct pim_upstream *starup = up->parent;
1227
1228 // iif == RPF_interfvace(S)
1229 if (up->rpf.source_nexthop.interface != incoming) {
1230 if (PIM_DEBUG_TRACE)
1231 zlog_debug(
1232 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1233 __PRETTY_FUNCTION__, incoming->name,
1234 up->rpf.source_nexthop.interface->name);
1235 return;
1236 }
1237
1238 // AND JoinDesired(S,G) == TRUE
1239 // FIXME
1240
1241 // DirectlyConnected(S) == TRUE
1242 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1243 up->sg.src)) {
1244 if (PIM_DEBUG_TRACE)
1245 zlog_debug("%s: %s is directly connected to the source",
1246 __PRETTY_FUNCTION__, up->sg_str);
1247 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1248 return;
1249 }
1250
1251 // OR RPF_interface(S) != RPF_interface(RP(G))
1252 if (!starup
1253 || up->rpf.source_nexthop
1254 .interface != starup->rpf.source_nexthop.interface) {
1255 if (PIM_DEBUG_TRACE)
1256 zlog_debug(
1257 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1258 __PRETTY_FUNCTION__, up->sg_str);
1259 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1260 return;
1261 }
1262
1263 // OR inherited_olist(S,G,rpt) == NULL
1264 if (pim_upstream_is_sg_rpt(up)
1265 && pim_upstream_empty_inherited_olist(up)) {
1266 if (PIM_DEBUG_TRACE)
1267 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1268 __PRETTY_FUNCTION__, up->sg_str);
1269 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1270 return;
1271 }
1272
1273 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1274 // ( RPF'(S,G) != NULL ) )
1275 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1276 if (PIM_DEBUG_TRACE)
1277 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1278 __PRETTY_FUNCTION__, up->sg_str);
1279 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1280 return;
1281 }
1282
1283 return;
3a66b17b 1284}
80d9c3a0 1285
d62a17ae 1286const char *pim_upstream_state2str(enum pim_upstream_state join_state)
d7259eac 1287{
d62a17ae 1288 switch (join_state) {
1289 case PIM_UPSTREAM_NOTJOINED:
1290 return "NotJoined";
1291 break;
1292 case PIM_UPSTREAM_JOINED:
1293 return "Joined";
1294 break;
1295 }
1296 return "Unknown";
d7259eac 1297}
627ed2a3 1298
d62a17ae 1299const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
e0e127b0 1300{
d62a17ae 1301 switch (reg_state) {
1302 case PIM_REG_NOINFO:
1303 strcpy(state_str, "RegNoInfo");
1304 break;
1305 case PIM_REG_JOIN:
1306 strcpy(state_str, "RegJoined");
1307 break;
1308 case PIM_REG_JOIN_PENDING:
1309 strcpy(state_str, "RegJoinPend");
1310 break;
1311 case PIM_REG_PRUNE:
1312 strcpy(state_str, "RegPrune");
1313 break;
1314 default:
1315 strcpy(state_str, "RegUnknown");
1316 }
1317 return state_str;
e0e127b0 1318}
1319
d62a17ae 1320static int pim_upstream_register_stop_timer(struct thread *t)
627ed2a3 1321{
d62a17ae 1322 struct pim_interface *pim_ifp;
8e5f97e3 1323 struct pim_instance *pim;
d62a17ae 1324 struct pim_upstream *up;
1325 struct pim_rpf *rpg;
1326 struct ip ip_hdr;
1327 up = THREAD_ARG(t);
8e5f97e3 1328 pim = up->channel_oil->pim;
d62a17ae 1329
1330 if (PIM_DEBUG_TRACE) {
1331 char state_str[PIM_REG_STATE_STR_LEN];
8dbdb215
DS
1332 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1333 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1334 pim_reg_state2str(up->reg_state, state_str));
1335 }
1336
1337 switch (up->reg_state) {
1338 case PIM_REG_JOIN_PENDING:
1339 up->reg_state = PIM_REG_JOIN;
8e5f97e3 1340 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1341 PIM_OIF_FLAG_PROTO_PIM);
1342 break;
1343 case PIM_REG_JOIN:
1344 break;
1345 case PIM_REG_PRUNE:
1346 pim_ifp = up->rpf.source_nexthop.interface->info;
1347 if (!pim_ifp) {
1348 if (PIM_DEBUG_TRACE)
1349 zlog_debug(
1350 "%s: Interface: %s is not configured for pim",
1351 __PRETTY_FUNCTION__,
1352 up->rpf.source_nexthop.interface->name);
1353 return 0;
1354 }
1355 up->reg_state = PIM_REG_JOIN_PENDING;
1356 pim_upstream_start_register_stop_timer(up, 1);
1357
1358 if (((up->channel_oil->cc.lastused / 100)
2f5b0028 1359 > pim->keep_alive_time)
d9c9a9ee 1360 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
d62a17ae 1361 if (PIM_DEBUG_TRACE)
1362 zlog_debug(
1363 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1364 __PRETTY_FUNCTION__);
1365 return 0;
1366 }
d9c9a9ee 1367 rpg = RP(pim_ifp->pim, up->sg.grp);
1e7a3a2a
DS
1368 if (!rpg) {
1369 if (PIM_DEBUG_TRACE)
1370 zlog_debug(
1371 "%s: Cannot send register for %s no RPF to the RP",
1372 __PRETTY_FUNCTION__, up->sg_str);
1373 return 0;
1374 }
d62a17ae 1375 memset(&ip_hdr, 0, sizeof(struct ip));
1376 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1377 ip_hdr.ip_hl = 5;
1378 ip_hdr.ip_v = 4;
1379 ip_hdr.ip_src = up->sg.src;
1380 ip_hdr.ip_dst = up->sg.grp;
1381 ip_hdr.ip_len = htons(20);
1382 // checksum is broken
1383 pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
1384 pim_ifp->primary_address, rpg, 1, up);
1385 break;
1386 default:
1387 break;
70e7fda8 1388 }
d62a17ae 1389
1390 return 0;
627ed2a3
DS
1391}
1392
d62a17ae 1393void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1394 int null_register)
627ed2a3 1395{
d62a17ae 1396 uint32_t time;
1397
1398 THREAD_TIMER_OFF(up->t_rs_timer);
1399
1400 if (!null_register) {
1401 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1402 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1403 time = lower + (random() % (upper - lower + 1))
1404 - PIM_REGISTER_PROBE_PERIOD;
1405 } else
1406 time = PIM_REGISTER_PROBE_PERIOD;
1407
1408 if (PIM_DEBUG_TRACE) {
1409 zlog_debug(
1410 "%s: (S,G)=%s Starting upstream register stop timer %d",
1411 __PRETTY_FUNCTION__, up->sg_str, time);
1412 }
1413 thread_add_timer(master, pim_upstream_register_stop_timer, up, time,
1414 &up->t_rs_timer);
627ed2a3 1415}
4fdc8f36 1416
9b29ea95
DS
1417int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1418 struct pim_upstream *up)
4fdc8f36 1419{
d62a17ae 1420 struct interface *ifp;
1421 struct pim_interface *pim_ifp = NULL;
1422 struct pim_ifchannel *ch, *starch;
d62a17ae 1423 struct pim_upstream *starup = up->parent;
1424 int output_intf = 0;
1425
1426 if (up->rpf.source_nexthop.interface)
1427 pim_ifp = up->rpf.source_nexthop.interface->info;
1428 else {
1429 if (PIM_DEBUG_TRACE)
1430 zlog_debug("%s: up %s RPF is not present",
1431 __PRETTY_FUNCTION__, up->sg_str);
1432 }
1433 if (pim_ifp && !up->channel_oil)
611925dc
DS
1434 up->channel_oil = pim_channel_oil_add(
1435 pim, &up->sg, pim_ifp->mroute_vif_index);
d62a17ae 1436
451fda4f 1437 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1438 if (!ifp->info)
1439 continue;
1440
1441 ch = pim_ifchannel_find(ifp, &up->sg);
1442
1443 if (starup)
1444 starch = pim_ifchannel_find(ifp, &starup->sg);
1445 else
1446 starch = NULL;
1447
1448 if (!ch && !starch)
1449 continue;
1450
1451 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1452 starch)) {
1453 int flag = PIM_OIF_FLAG_PROTO_PIM;
1454
1455 if (!ch)
1456 flag = PIM_OIF_FLAG_PROTO_STAR;
1457
1458 pim_channel_add_oif(up->channel_oil, ifp, flag);
1459 output_intf++;
1460 }
1461 }
1462
1463 return output_intf;
b5183fd1
DS
1464}
1465
1466/*
1467 * For a given upstream, determine the inherited_olist
1468 * and apply it.
1469 *
1470 * inherited_olist(S,G,rpt) =
1471 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1472 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1473 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1474 *
1475 * inherited_olist(S,G) =
1476 * inherited_olist(S,G,rpt) (+)
1477 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1478 *
1479 * return 1 if there are any output interfaces
1480 * return 0 if there are not any output interfaces
1481 */
9b29ea95
DS
1482int pim_upstream_inherited_olist(struct pim_instance *pim,
1483 struct pim_upstream *up)
b5183fd1 1484{
9b29ea95 1485 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1486
1487 /*
1488 * If we have output_intf switch state to Join and work like normal
1489 * If we don't have an output_intf that means we are probably a
1490 * switch on a stick so turn on forwarding to just accept the
1491 * incoming packets so we don't bother the other stuff!
1492 */
1493 if (output_intf)
1eca8576 1494 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 1495 else
1496 forward_on(up);
1497
1498 return output_intf;
4fdc8f36 1499}
d3dd1804 1500
d62a17ae 1501int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
80d9c3a0 1502{
d62a17ae 1503 return pim_channel_oil_empty(up->channel_oil);
80d9c3a0
DS
1504}
1505
d3dd1804
DS
1506/*
1507 * When we have a new neighbor,
1508 * find upstreams that don't have their rpf_addr
1509 * set and see if the new neighbor allows
1510 * the join to be sent
1511 */
9b29ea95 1512void pim_upstream_find_new_rpf(struct pim_instance *pim)
d3dd1804 1513{
d62a17ae 1514 struct listnode *up_node;
1515 struct listnode *up_nextnode;
1516 struct pim_upstream *up;
1517
1518 /*
1519 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1520 */
9b29ea95 1521 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
d62a17ae 1522 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1523 if (PIM_DEBUG_TRACE)
1524 zlog_debug(
1525 "Upstream %s without a path to send join, checking",
1526 up->sg_str);
2002dcdb 1527 pim_rpf_update(pim, up, NULL, 1);
d62a17ae 1528 }
d3dd1804 1529 }
d3dd1804 1530}
0f588989 1531
7c591950 1532unsigned int pim_upstream_hash_key(void *arg)
0f588989 1533{
d62a17ae 1534 struct pim_upstream *up = (struct pim_upstream *)arg;
0f588989 1535
d62a17ae 1536 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
0f588989
DS
1537}
1538
9b29ea95 1539void pim_upstream_terminate(struct pim_instance *pim)
0f588989 1540{
172e45dc
DS
1541 struct listnode *node, *nnode;
1542 struct pim_upstream *up;
1543
1544 if (pim->upstream_list) {
1545 for (ALL_LIST_ELEMENTS(pim->upstream_list, node, nnode, up))
1546 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1547
affe9e99 1548 list_delete_and_null(&pim->upstream_list);
172e45dc 1549 }
0f588989 1550
9b29ea95
DS
1551 if (pim->upstream_hash)
1552 hash_free(pim->upstream_hash);
1553 pim->upstream_hash = NULL;
0f588989
DS
1554}
1555
7c591950 1556int pim_upstream_equal(const void *arg1, const void *arg2)
0f588989 1557{
d62a17ae 1558 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1559 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
0f588989 1560
d62a17ae 1561 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1562 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
1563 return 1;
0f588989 1564
d62a17ae 1565 return 0;
0f588989
DS
1566}
1567
1bf16443 1568/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1569 * the cases where kat has to be restarted on rxing traffic -
1570 *
1571 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1572 * set KeepaliveTimer(S,G) to Keepalive_Period
1573 * # Note: a register state transition or UpstreamJPState(S,G)
1574 * # transition may happen as a result of restarting
1575 * # KeepaliveTimer, and must be dealt with here.
1576 * }
1577 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1578 * inherited_olist(S,G) != NULL ) {
1579 * set KeepaliveTimer(S,G) to Keepalive_Period
1580 * }
1581 */
1582static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1583{
8e5f97e3
DS
1584 struct pim_instance *pim = up->channel_oil->pim;
1585
d62a17ae 1586 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1587 * so we will skip that here */
1588 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1589 up->sg.src)) {
1590 return true;
1591 }
1592
1593 if ((up->join_state == PIM_UPSTREAM_JOINED)
1594 && !pim_upstream_empty_inherited_olist(up)) {
1595 /* XXX: I have added this RP check just for 3.2 and it's a
1596 * digression from
1597 * what rfc-4601 says. Till now we were only running KAT on FHR
1598 * and RP and
1599 * there is some angst around making the change to run it all
1600 * routers that
1601 * maintain the (S, G) state. This is tracked via CM-13601 and
1602 * MUST be
1603 * removed to handle spt turn-arounds correctly in a 3-tier clos
1604 */
8e5f97e3 1605 if (I_am_RP(pim, up->sg.grp))
d62a17ae 1606 return true;
1607 }
1608
1609 return false;
1bf16443 1610}
1611
9c5e4d62
DS
1612/*
1613 * Code to check and see if we've received packets on a S,G mroute
1614 * and if so to set the SPT bit appropriately
1615 */
d62a17ae 1616static void pim_upstream_sg_running(void *arg)
9c5e4d62 1617{
d62a17ae 1618 struct pim_upstream *up = (struct pim_upstream *)arg;
8e5f97e3 1619 struct pim_instance *pim = up->channel_oil->pim;
d62a17ae 1620
1621 // No packet can have arrived here if this is the case
8e5f97e3 1622 if (!up->channel_oil->installed) {
d62a17ae 1623 if (PIM_DEBUG_TRACE)
6c65db5f 1624 zlog_debug("%s: %s[%s] is not installed in mroute",
996c9314
LB
1625 __PRETTY_FUNCTION__, up->sg_str,
1626 pim->vrf->name);
d62a17ae 1627 return;
1628 }
1629
1630 /*
1631 * This is a bit of a hack
1632 * We've noted that we should rescan but
1633 * we've missed the window for doing so in
1634 * pim_zebra.c for some reason. I am
1635 * only doing this at this point in time
1636 * to get us up and working for the moment
1637 */
1638 if (up->channel_oil->oil_inherited_rescan) {
1639 if (PIM_DEBUG_TRACE)
1640 zlog_debug(
8dbdb215 1641 "%s: Handling unscanned inherited_olist for %s[%s]",
996c9314
LB
1642 __PRETTY_FUNCTION__, up->sg_str,
1643 pim->vrf->name);
8e5f97e3 1644 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1645 up->channel_oil->oil_inherited_rescan = 0;
1646 }
1647 pim_mroute_update_counters(up->channel_oil);
1648
1649 // Have we seen packets?
1650 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1651 && (up->channel_oil->cc.lastused / 100 > 30)) {
1652 if (PIM_DEBUG_TRACE) {
1653 zlog_debug(
8dbdb215
DS
1654 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1655 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1656 up->channel_oil->cc.oldpktcnt,
1657 up->channel_oil->cc.pktcnt,
1658 up->channel_oil->cc.lastused / 100);
1659 }
1660 return;
e43b8697 1661 }
d62a17ae 1662
1663 if (pim_upstream_kat_start_ok(up)) {
1664 /* Add a source reference to the stream if
1665 * one doesn't already exist */
1666 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1667 if (PIM_DEBUG_TRACE)
1668 zlog_debug(
8dbdb215
DS
1669 "source reference created on kat restart %s[%s]",
1670 up->sg_str, pim->vrf->name);
d62a17ae 1671
1672 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1673 __PRETTY_FUNCTION__);
1674 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1675 pim_upstream_fhr_kat_start(up);
1676 }
19b807ca 1677 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1678 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
19b807ca 1679 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1680
1681 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
1682 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
850a9f99 1683 }
d62a17ae 1684 return;
9c5e4d62
DS
1685}
1686
9b29ea95 1687void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
a7b2b1e2 1688{
d62a17ae 1689 struct pim_upstream *up;
1690 struct listnode *node;
a7b2b1e2 1691
9b29ea95 1692 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1693 if (up->sg.src.s_addr != INADDR_ANY)
1694 continue;
a7b2b1e2 1695
d62a17ae 1696 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1697 continue;
a7b2b1e2 1698
9b29ea95 1699 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1700 PIM_OIF_FLAG_PROTO_IGMP);
1701 }
a7b2b1e2
DS
1702}
1703
9b29ea95
DS
1704void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
1705 struct prefix_list *pl)
df94f9a9 1706{
d62a17ae 1707 const char *pname = prefix_list_name(pl);
df94f9a9 1708
9b29ea95
DS
1709 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
1710 pim_upstream_remove_lhr_star_pimreg(pim, pname);
d62a17ae 1711 }
df94f9a9
DS
1712}
1713
1714/*
1715 * nlist -> The new prefix list
1716 *
1717 * Per Group Application of pimreg to the OIL
1718 * If the prefix list tells us DENY then
1719 * we need to Switchover to SPT immediate
1720 * so add the pimreg.
1721 * If the prefix list tells us to ACCEPT than
1722 * we need to Never do the SPT so remove
1723 * the interface
1724 *
1725 */
9b29ea95
DS
1726void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
1727 const char *nlist)
a7b2b1e2 1728{
d62a17ae 1729 struct pim_upstream *up;
1730 struct listnode *node;
1731 struct prefix_list *np;
1732 struct prefix g;
1733 enum prefix_list_type apply_new;
1734
1735 np = prefix_list_lookup(AFI_IP, nlist);
1736
1737 g.family = AF_INET;
1738 g.prefixlen = IPV4_MAX_PREFIXLEN;
1739
9b29ea95 1740 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1741 if (up->sg.src.s_addr != INADDR_ANY)
1742 continue;
1743
1744 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1745 continue;
1746
1747 if (!nlist) {
9b29ea95 1748 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1749 PIM_OIF_FLAG_PROTO_IGMP);
1750 continue;
1751 }
1752 g.u.prefix4 = up->sg.grp;
1753 apply_new = prefix_list_apply(np, &g);
1754 if (apply_new == PREFIX_DENY)
9b29ea95 1755 pim_channel_add_oif(up->channel_oil, pim->regiface,
d62a17ae 1756 PIM_OIF_FLAG_PROTO_IGMP);
1757 else
9b29ea95 1758 pim_channel_del_oif(up->channel_oil, pim->regiface,
d62a17ae 1759 PIM_OIF_FLAG_PROTO_IGMP);
1760 }
a7b2b1e2
DS
1761}
1762
9b29ea95 1763void pim_upstream_init(struct pim_instance *pim)
0f588989 1764{
9fb302f4
DS
1765 char hash_name[64];
1766
9b29ea95 1767 pim->upstream_sg_wheel =
d62a17ae 1768 wheel_init(master, 31000, 100, pim_upstream_hash_key,
1769 pim_upstream_sg_running);
9fb302f4 1770
996c9314 1771 snprintf(hash_name, 64, "PIM %s Upstream Hash", pim->vrf->name);
9b29ea95 1772 pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
9fb302f4 1773 pim_upstream_equal, hash_name);
d62a17ae 1774
9b29ea95 1775 pim->upstream_list = list_new();
9b29ea95 1776 pim->upstream_list->cmp = pim_upstream_compare;
0f588989 1777}