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