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