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