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