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