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