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