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