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