]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: we cannot change the Joined state based on RPF resolution
[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. */
539 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || !up->t_ka_timer)
540 continue;
541
6f439a70 542 if (pim_is_grp_ssm(pim, up->sg.grp)) {
d62a17ae 543 /* clear the register state for SSM groups */
544 if (up->reg_state != PIM_REG_NOINFO) {
545 if (PIM_DEBUG_PIM_EVENTS)
546 zlog_debug(
547 "Clear register for %s as G is now SSM",
548 up->sg_str);
549 /* remove regiface from the OIL if it is there*/
550 pim_channel_del_oif(up->channel_oil,
9b29ea95 551 pim->regiface,
1b249e70
AK
552 PIM_OIF_FLAG_PROTO_PIM,
553 __func__);
d62a17ae 554 up->reg_state = PIM_REG_NOINFO;
555 }
556 } else {
557 /* register ASM sources with the RP */
558 if (up->reg_state == PIM_REG_NOINFO) {
559 if (PIM_DEBUG_PIM_EVENTS)
560 zlog_debug(
561 "Register %s as G is now ASM",
562 up->sg_str);
563 pim_channel_add_oif(up->channel_oil,
9b29ea95 564 pim->regiface,
1b249e70
AK
565 PIM_OIF_FLAG_PROTO_PIM,
566 __func__);
d62a17ae 567 up->reg_state = PIM_REG_JOIN;
568 }
569 }
570 }
15a5dafe 571}
572
69e3538c
AK
573/* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
574 * forward a S -
575 * 1. along the SPT if SPTbit is set
576 * 2. and along the RPT if SPTbit is not set
577 * If forwarding is hw accelerated i.e. control and dataplane components
578 * are separate you may not be able to reliably set SPT bit on intermediate
579 * routers while still fowarding on the (S,G,rpt).
580 *
581 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
582 * criteria to decide between using the RPT vs. SPT for forwarding.
583 */
584void pim_upstream_update_use_rpt(struct pim_upstream *up,
585 bool update_mroute)
586{
587 bool old_use_rpt;
588 bool new_use_rpt;
589
590 if (up->sg.src.s_addr == INADDR_ANY)
591 return;
592
593 old_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
594
595 /* We will use the SPT (IIF=RPF_interface(S) if -
596 * 1. We have decided to join the SPT
597 * 2. We are FHR
598 * 3. Source is directly connected
599 * 4. We are RP (parent's IIF is lo or vrf-device)
600 * In all other cases the source will stay along the RPT and
601 * IIF=RPF_interface(RP).
602 */
603 if (up->join_state == PIM_UPSTREAM_JOINED ||
604 PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
605 pim_if_connected_to_source(
606 up->rpf.source_nexthop.interface,
607 up->sg.src) ||
608 /* XXX - need to switch this to a more efficient
609 * lookup API
610 */
611 I_am_RP(up->pim, up->sg.grp))
612 /* use SPT */
613 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags);
614 else
615 /* use RPT */
616 PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags);
617
618 new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
619 if (old_use_rpt != new_use_rpt) {
620 if (PIM_DEBUG_PIM_EVENTS)
621 zlog_debug("%s switched from %s to %s",
622 up->sg_str,
623 old_use_rpt?"RPT":"SPT",
624 new_use_rpt?"RPT":"SPT");
625 if (update_mroute)
626 pim_upstream_mroute_add(up->channel_oil, __func__);
627 }
628}
629
a749b900
AK
630/* some events like RP change require re-evaluation of SGrpt across
631 * all groups
632 */
633void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
634{
635 struct pim_upstream *up;
636 struct listnode *node;
637
638 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
639 if (up->sg.src.s_addr == INADDR_ANY)
640 continue;
641
642 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
643 }
644}
645
1eca8576 646void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
d62a17ae 647 enum pim_upstream_state new_state)
12e41d03 648{
d62a17ae 649 enum pim_upstream_state old_state = up->join_state;
650
957d93ea 651 if (up->upstream_addr.s_addr == INADDR_ANY) {
47e3ce59
SP
652 if (PIM_DEBUG_PIM_EVENTS)
653 zlog_debug("%s: RPF not configured for %s",
654 __PRETTY_FUNCTION__, up->sg_str);
957d93ea
SP
655 return;
656 }
657
658 if (!up->rpf.source_nexthop.interface) {
47e3ce59
SP
659 if (PIM_DEBUG_PIM_EVENTS)
660 zlog_debug("%s: RP not reachable for %s",
661 __PRETTY_FUNCTION__, up->sg_str);
957d93ea
SP
662 return;
663 }
664
d62a17ae 665 if (PIM_DEBUG_PIM_EVENTS) {
666 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
667 __PRETTY_FUNCTION__, up->sg_str,
668 pim_upstream_state2str(up->join_state),
669 pim_upstream_state2str(new_state));
670 }
671
672 up->join_state = new_state;
673 if (old_state != new_state)
674 up->state_transition = pim_time_monotonic_sec();
675
676 pim_upstream_update_assert_tracking_desired(up);
677
678 if (new_state == PIM_UPSTREAM_JOINED) {
b077f571 679 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 680 if (old_state != PIM_UPSTREAM_JOINED) {
681 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
b077f571 682
1eca8576 683 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 684 if (pim_upstream_could_register(up)) {
685 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
686 if (!old_fhr
687 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
688 up->flags)) {
689 pim_upstream_keep_alive_timer_start(
19b807ca 690 up, pim->keep_alive_time);
d62a17ae 691 pim_register_join(up);
692 }
693 } else {
694 pim_upstream_send_join(up);
695 join_timer_start(up);
696 }
d62a17ae 697 }
698 } else {
699
700 forward_off(up);
701 if (old_state == PIM_UPSTREAM_JOINED)
1eca8576 702 pim_msdp_up_join_state_changed(pim, up);
d62a17ae 703
704 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
705 RP.
706 If I am RP for G then send S,G prune to its IIF. */
707 if (pim_upstream_is_sg_rpt(up) && up->parent
1eca8576 708 && !I_am_RP(pim, up->sg.grp)) {
d62a17ae 709 if (PIM_DEBUG_PIM_TRACE_DETAIL)
710 zlog_debug(
957d93ea
SP
711 "%s: *,G IIF %s S,G IIF %s ",
712 __PRETTY_FUNCTION__,
713 up->parent->rpf.source_nexthop.interface ?
714 up->parent->rpf.source_nexthop.interface->name
715 : "Unknown",
716 up->rpf.source_nexthop.interface ?
717 up->rpf.source_nexthop.interface->name :
718 "Unknown");
d62a17ae 719 pim_jp_agg_single_upstream_send(&up->parent->rpf,
720 up->parent,
721 1 /* (W,G) Join */);
722 } else
723 pim_jp_agg_single_upstream_send(&up->rpf, up,
724 0 /* prune */);
725 join_timer_stop(up);
726 }
69e3538c
AK
727
728 if (old_state != new_state)
729 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
12e41d03
DL
730}
731
d62a17ae 732int pim_upstream_compare(void *arg1, void *arg2)
03417ccd 733{
d62a17ae 734 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
735 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
03417ccd 736
d62a17ae 737 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
738 return -1;
03417ccd 739
d62a17ae 740 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
741 return 1;
03417ccd 742
d62a17ae 743 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
744 return -1;
03417ccd 745
d62a17ae 746 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
747 return 1;
03417ccd 748
d62a17ae 749 return 0;
03417ccd
DS
750}
751
6a5de0ad
AK
752void pim_upstream_fill_static_iif(struct pim_upstream *up,
753 struct interface *incoming)
754{
755 up->rpf.source_nexthop.interface = incoming;
756
757 /* reset other parameters to matched a connected incoming interface */
758 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
759 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
760 PIM_NET_INADDR_ANY;
761 up->rpf.source_nexthop.mrib_metric_preference =
762 ZEBRA_CONNECT_DISTANCE_DEFAULT;
763 up->rpf.source_nexthop.mrib_route_metric = 0;
764 up->rpf.rpf_addr.family = AF_INET;
765 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
766
767}
768
2002dcdb
DS
769static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
770 struct prefix_sg *sg,
771 struct interface *incoming,
0885a9f1
DS
772 int flags,
773 struct pim_ifchannel *ch)
12e41d03 774{
d62a17ae 775 enum pim_rpf_result rpf_result;
776 struct pim_interface *pim_ifp;
777 struct pim_upstream *up;
778
779 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
d62a17ae 780
69e3538c 781 up->pim = pim;
d62a17ae 782 up->sg = *sg;
783 pim_str_sg_set(sg, up->sg_str);
0885a9f1
DS
784 if (ch)
785 ch->upstream = up;
786
9b29ea95 787 up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
732c209c
SP
788 /* Set up->upstream_addr as INADDR_ANY, if RP is not
789 * configured and retain the upstream data structure
790 */
d9c9a9ee
DS
791 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
792 sg->grp)) {
23fc858a 793 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 794 zlog_debug("%s: Received a (*,G) with no RP configured",
795 __PRETTY_FUNCTION__);
d62a17ae 796 }
797
9b29ea95 798 up->parent = pim_upstream_find_parent(pim, up);
d62a17ae 799 if (up->sg.src.s_addr == INADDR_ANY) {
800 up->sources = list_new();
801 up->sources->cmp = pim_upstream_compare;
802 } else
803 up->sources = NULL;
804
9b29ea95 805 pim_upstream_find_new_children(pim, up);
d62a17ae 806 up->flags = flags;
807 up->ref_count = 1;
808 up->t_join_timer = NULL;
809 up->t_ka_timer = NULL;
810 up->t_rs_timer = NULL;
811 up->t_msdp_reg_timer = NULL;
812 up->join_state = PIM_UPSTREAM_NOTJOINED;
813 up->reg_state = PIM_REG_NOINFO;
814 up->state_transition = pim_time_monotonic_sec();
46dd6edb 815 up->channel_oil =
7984af18 816 pim_channel_oil_add(pim, &up->sg, __PRETTY_FUNCTION__);
d62a17ae 817 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
818
819 up->rpf.source_nexthop.interface = NULL;
820 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
821 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
822 PIM_NET_INADDR_ANY;
823 up->rpf.source_nexthop.mrib_metric_preference =
d17612dd 824 router->infinite_assert_metric.metric_preference;
d62a17ae 825 up->rpf.source_nexthop.mrib_route_metric =
d17612dd 826 router->infinite_assert_metric.route_metric;
d62a17ae 827 up->rpf.rpf_addr.family = AF_INET;
828 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
829
830 up->ifchannels = list_new();
831 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
832
833 if (up->sg.src.s_addr != INADDR_ANY)
9b29ea95 834 wheel_add_item(pim->upstream_sg_wheel, up);
d62a17ae 835
02434c43
DS
836 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
837 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
6a5de0ad
AK
838 pim_upstream_fill_static_iif(up, incoming);
839 pim_ifp = up->rpf.source_nexthop.interface->info;
840 assert(pim_ifp);
7984af18 841 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
02434c43
DS
842
843 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
844 pim_upstream_keep_alive_timer_start(
845 up, pim->keep_alive_time);
46dd6edb 846 } else if (up->upstream_addr.s_addr != INADDR_ANY) {
ae14da48 847 rpf_result = pim_rpf_update(pim, up, NULL);
732c209c 848 if (rpf_result == PIM_RPF_FAILURE) {
23fc858a 849 if (PIM_DEBUG_PIM_TRACE)
732c209c
SP
850 zlog_debug(
851 "%s: Attempting to create upstream(%s), Unable to RPF for source",
852 __PRETTY_FUNCTION__, up->sg_str);
d62a17ae 853 }
854
732c209c
SP
855 if (up->rpf.source_nexthop.interface) {
856 pim_ifp = up->rpf.source_nexthop.interface->info;
857 if (pim_ifp)
7984af18
AK
858 pim_upstream_mroute_iif_update(up->channel_oil,
859 __func__);
732c209c 860 }
69e3538c
AK
861 pim_upstream_update_use_rpt(up,
862 false /*update_mroute*/);
d62a17ae 863 }
864
9b29ea95 865 listnode_add_sort(pim->upstream_list, up);
d62a17ae 866
23fc858a 867 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 868 zlog_debug(
869 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
870 __PRETTY_FUNCTION__, up->sg_str,
871 inet_ntoa(up->upstream_addr), up->ref_count);
872 }
873
874 return up;
12e41d03
DL
875}
876
9b29ea95
DS
877struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
878 struct prefix_sg *sg)
12e41d03 879{
d62a17ae 880 struct pim_upstream lookup;
881 struct pim_upstream *up = NULL;
12e41d03 882
d62a17ae 883 lookup.sg = *sg;
9b29ea95 884 up = hash_lookup(pim->upstream_hash, &lookup);
d62a17ae 885 return up;
12e41d03
DL
886}
887
d62a17ae 888struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
69e3538c
AK
889 struct interface *incoming,
890 int flags, const char *name)
e711cd3c 891{
69e3538c 892 struct pim_interface *pim_ifp = incoming->info;
d62a17ae 893
69e3538c
AK
894 return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
895 NULL));
e711cd3c
DS
896}
897
d62a17ae 898void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1bf16443 899{
69e3538c
AK
900 /* when we go from non-FHR to FHR we need to re-eval traffic
901 * forwarding path
902 */
903 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
904 PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
905 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
906 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
907 }
908
d62a17ae 909 up->flags |= flags;
910 ++up->ref_count;
23fc858a 911 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 912 zlog_debug("%s(%s): upstream %s ref count %d increment",
913 __PRETTY_FUNCTION__, name, up->sg_str,
914 up->ref_count);
1bf16443 915}
916
2002dcdb
DS
917struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
918 struct prefix_sg *sg,
d62a17ae 919 struct interface *incoming, int flags,
0885a9f1
DS
920 const char *name,
921 struct pim_ifchannel *ch)
12e41d03 922{
d62a17ae 923 struct pim_upstream *up = NULL;
924 int found = 0;
9b29ea95 925
2002dcdb 926 up = pim_upstream_find(pim, sg);
d62a17ae 927 if (up) {
928 pim_upstream_ref(up, flags, name);
929 found = 1;
930 } else {
0885a9f1 931 up = pim_upstream_new(pim, sg, incoming, flags, ch);
d62a17ae 932 }
933
23fc858a 934 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 935 if (up) {
936 char buf[PREFIX2STR_BUFFER];
937 prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf));
938 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
f4075cb4 939 __PRETTY_FUNCTION__, name,
55785900 940 up->sg_str, buf, up->rpf.source_nexthop.interface ?
957d93ea 941 up->rpf.source_nexthop.interface->name : "Unknown" ,
55785900 942 found, up->ref_count);
d62a17ae 943 } else
944 zlog_debug("%s(%s): (%s) failure to create",
945 __PRETTY_FUNCTION__, name,
946 pim_str_sg_dump(sg));
947 }
12e41d03 948
d62a17ae 949 return up;
12e41d03
DL
950}
951
a53a9b3e
AK
952/*
953 * Passed in up must be the upstream for ch. starch is NULL if no
954 * information
955 * This function is copied over from
956 * pim_upstream_evaluate_join_desired_interface but limited to
957 * parent (*,G)'s includes/joins.
958 */
959int pim_upstream_eval_inherit_if(struct pim_upstream *up,
960 struct pim_ifchannel *ch,
961 struct pim_ifchannel *starch)
962{
963 /* if there is an explicit prune for this interface we cannot
964 * add it to the OIL
965 */
966 if (ch) {
967 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
968 return 0;
969 }
970
971 /* Check if the OIF can be inherited fron the (*,G) entry
972 */
973 if (starch) {
974 if (!pim_macro_ch_lost_assert(starch)
975 && pim_macro_chisin_joins_or_include(starch))
976 return 1;
977 }
978
979 return 0;
980}
981
c8fc07cb
DS
982/*
983 * Passed in up must be the upstream for ch. starch is NULL if no
984 * information
985 */
d62a17ae 986int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
987 struct pim_ifchannel *ch,
988 struct pim_ifchannel *starch)
7a3ddda5 989{
d62a17ae 990 if (ch) {
991 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
992 return 0;
993
994 if (!pim_macro_ch_lost_assert(ch)
995 && pim_macro_chisin_joins_or_include(ch))
996 return 1;
997 }
998
999 /*
1000 * joins (*,G)
1001 */
1002 if (starch) {
a53a9b3e
AK
1003 /* XXX: check on this with donald
1004 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1005 * upstream flags?
1006 */
1007#if 0
d62a17ae 1008 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1009 return 0;
a53a9b3e 1010#endif
d62a17ae 1011
1012 if (!pim_macro_ch_lost_assert(starch)
1013 && pim_macro_chisin_joins_or_include(starch))
1014 return 1;
1015 }
1016
1017 return 0;
7a3ddda5
DS
1018}
1019
a53a9b3e
AK
1020/* Returns true if immediate OIL is empty and is used to evaluate
1021 * JoinDesired. See pim_upstream_evaluate_join_desired.
12e41d03 1022 */
a53a9b3e 1023static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
9b29ea95 1024 struct pim_upstream *up)
12e41d03 1025{
d62a17ae 1026 struct interface *ifp;
a53a9b3e 1027 struct pim_ifchannel *ch;
12e41d03 1028
451fda4f 1029 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1030 if (!ifp->info)
1031 continue;
c8fc07cb 1032
d62a17ae 1033 ch = pim_ifchannel_find(ifp, &up->sg);
a53a9b3e 1034 if (!ch)
d62a17ae 1035 continue;
12e41d03 1036
a53a9b3e
AK
1037 /* If we have even one immediate OIF we can return with
1038 * not-empty
1039 */
1040 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1041 NULL /* starch */))
1042 return false;
d62a17ae 1043 } /* scan iface channel list */
12e41d03 1044
a53a9b3e
AK
1045 /* immediate_oil is empty */
1046 return true;
1047}
1048
1049static bool pim_upstream_is_kat_running(struct pim_upstream *up)
1050{
1051 return (up->t_ka_timer != NULL);
1052}
1053
1054/*
1055 * bool JoinDesired(*,G) {
1056 * if (immediate_olist(*,G) != NULL)
1057 * return TRUE
1058 * else
1059 * return FALSE
1060 * }
1061 *
1062 * bool JoinDesired(S,G) {
1063 * return( immediate_olist(S,G) != NULL
1064 * OR ( KeepaliveTimer(S,G) is running
1065 * AND inherited_olist(S,G) != NULL ) )
1066 * }
1067 */
1068int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
1069 struct pim_upstream *up)
1070{
1071 bool empty_imm_oil;
1072 bool empty_inh_oil;
1073
1074 empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1075
1076 /* (*,G) */
1077 if (up->sg.src.s_addr == INADDR_ANY)
1078 return !empty_imm_oil;
1079
1080 /* (S,G) */
1081 if (!empty_imm_oil)
1082 return true;
1083 empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1084 if (!empty_inh_oil &&
1085 (pim_upstream_is_kat_running(up) ||
1086 I_am_RP(pim, up->sg.grp)))
1087 return true;
1088
1089 return false;
12e41d03
DL
1090}
1091
1092/*
1093 See also pim_upstream_evaluate_join_desired() above.
1094*/
9b29ea95
DS
1095void pim_upstream_update_join_desired(struct pim_instance *pim,
1096 struct pim_upstream *up)
12e41d03 1097{
d62a17ae 1098 int was_join_desired; /* boolean */
1099 int is_join_desired; /* boolean */
1100
1101 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1102
9b29ea95 1103 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
d62a17ae 1104 if (is_join_desired)
1105 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1106 else
1107 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1108
1109 /* switched from false to true */
47e3ce59 1110 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1eca8576 1111 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 1112 return;
1113 }
1114
1115 /* switched from true to false */
1116 if (!is_join_desired && was_join_desired) {
1eca8576 1117 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
d62a17ae 1118 return;
1119 }
12e41d03
DL
1120}
1121
1122/*
1123 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1124 Transitions from Joined State
1125 RPF'(S,G) GenID changes
1126
1127 The upstream (S,G) state machine remains in Joined state. If the
1128 Join Timer is set to expire in more than t_override seconds, reset
1129 it so that it expires after t_override seconds.
1130*/
9b29ea95
DS
1131void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
1132 struct in_addr neigh_addr)
12e41d03 1133{
d62a17ae 1134 struct listnode *up_node;
1135 struct listnode *up_nextnode;
1136 struct pim_upstream *up;
1137
1138 /*
1139 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1140 */
9b29ea95 1141 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
d62a17ae 1142
23fc858a 1143 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1144 char neigh_str[INET_ADDRSTRLEN];
1145 char rpf_addr_str[PREFIX_STRLEN];
1146 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
1147 sizeof(neigh_str));
1148 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
1149 sizeof(rpf_addr_str));
1150 zlog_debug(
8dbdb215 1151 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
996c9314
LB
1152 __PRETTY_FUNCTION__, neigh_str, up->sg_str,
1153 pim->vrf->name,
d62a17ae 1154 up->join_state == PIM_UPSTREAM_JOINED,
1155 rpf_addr_str);
1156 }
1157
1158 /* consider only (S,G) upstream in Joined state */
1159 if (up->join_state != PIM_UPSTREAM_JOINED)
1160 continue;
1161
1162 /* match RPF'(S,G)=neigh_addr */
1163 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
1164 continue;
1165
1166 pim_upstream_join_timer_decrease_to_t_override(
1167 "RPF'(S,G) GenID change", up);
1168 }
12e41d03
DL
1169}
1170
1171
1172void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1173 struct interface *old_rpf_ifp)
1174{
d62a17ae 1175 struct listnode *chnode;
1176 struct listnode *chnextnode;
1177 struct pim_ifchannel *ch;
1178
1179 /* search all ifchannels */
1180 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1181 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1182 if (
1183 /* RPF_interface(S) was NOT I */
1184 (old_rpf_ifp == ch->interface) &&
1185 /* RPF_interface(S) stopped being I */
1186 (ch->upstream->rpf.source_nexthop
957d93ea
SP
1187 .interface) &&
1188 (ch->upstream->rpf.source_nexthop
1189 .interface != ch->interface)) {
d62a17ae 1190 assert_action_a5(ch);
1191 }
1192 } /* PIM_IFASSERT_I_AM_LOSER */
1193
1194 pim_ifchannel_update_assert_tracking_desired(ch);
1195 }
12e41d03
DL
1196}
1197
1198void pim_upstream_update_could_assert(struct pim_upstream *up)
1199{
d62a17ae 1200 struct listnode *chnode;
1201 struct listnode *chnextnode;
1202 struct pim_ifchannel *ch;
1203
1204 /* scan per-interface (S,G) state */
1205 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1206 pim_ifchannel_update_could_assert(ch);
1207 } /* scan iface channel list */
12e41d03
DL
1208}
1209
1210void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1211{
d62a17ae 1212 struct listnode *chnode;
1213 struct listnode *chnextnode;
1214 struct pim_ifchannel *ch;
12e41d03 1215
d62a17ae 1216 /* scan per-interface (S,G) state */
1217 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1218 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 1219
d62a17ae 1220 } /* scan iface channel list */
12e41d03
DL
1221}
1222
1223static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1224{
d62a17ae 1225 struct listnode *chnode;
1226 struct listnode *chnextnode;
1227 struct pim_interface *pim_ifp;
1228 struct pim_ifchannel *ch;
1229
1230 /* scan per-interface (S,G) state */
1231 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1232 if (!ch->interface)
1233 continue;
1234 pim_ifp = ch->interface->info;
1235 if (!pim_ifp)
1236 continue;
1237
1238 pim_ifchannel_update_assert_tracking_desired(ch);
1239
1240 } /* scan iface channel list */
12e41d03 1241}
f14248dd 1242
1bf16443 1243/* When kat is stopped CouldRegister goes to false so we need to
1244 * transition the (S, G) on FHR to NI state and remove reg tunnel
1245 * from the OIL */
9b29ea95
DS
1246static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1247 struct pim_upstream *up)
1bf16443 1248{
d62a17ae 1249 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1250 return;
1251
23fc858a 1252 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1253 zlog_debug("kat expired on %s; clear fhr reg state",
1254 up->sg_str);
1255
1256 /* stop reg-stop timer */
1257 THREAD_OFF(up->t_rs_timer);
1258 /* remove regiface from the OIL if it is there*/
9b29ea95 1259 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 1260 PIM_OIF_FLAG_PROTO_PIM, __func__);
d62a17ae 1261 /* clear the register state */
1262 up->reg_state = PIM_REG_NOINFO;
1263 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1bf16443 1264}
1265
1266/* When kat is started CouldRegister can go to true. And if it does we
1267 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1268 * to the OIL */
1269static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1270{
d62a17ae 1271 if (pim_upstream_could_register(up)) {
23fc858a 1272 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1273 zlog_debug(
1274 "kat started on %s; set fhr reg state to joined",
1275 up->sg_str);
1276
1277 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1278 if (up->reg_state == PIM_REG_NOINFO)
1279 pim_register_join(up);
69e3538c 1280 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
d62a17ae 1281 }
1bf16443 1282}
1283
f14248dd
DS
1284/*
1285 * On an RP, the PMBR value must be cleared when the
1286 * Keepalive Timer expires
1bf16443 1287 * KAT expiry indicates that flow is inactive. If the flow was created or
1288 * maintained by activity now is the time to deref it.
f14248dd 1289 */
ff459c36
AK
1290struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1291 struct pim_upstream *up)
f14248dd 1292{
8e5f97e3 1293 struct pim_instance *pim;
d62a17ae 1294
8e5f97e3 1295 pim = up->channel_oil->pim;
d62a17ae 1296
820b4a40
AK
1297 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
1298 /* if the router is a PIM vxlan encapsulator we prevent expiry
1299 * of KAT as the mroute is pre-setup without any traffic
1300 */
1301 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
ff459c36 1302 return up;
820b4a40
AK
1303 }
1304
8e5f97e3 1305 if (I_am_RP(pim, up->sg.grp)) {
d62a17ae 1306 pim_br_clear_pmbr(&up->sg);
1307 /*
1308 * We need to do more here :)
1309 * But this is the start.
1310 */
1311 }
1312
1313 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1314 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1315
a53a9b3e
AK
1316 /* JoinDesired can change when KAT is started or stopped */
1317 pim_upstream_update_join_desired(pim, up);
1318
d62a17ae 1319 /* if entry was created because of activity we need to deref it */
1320 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
8e5f97e3 1321 pim_upstream_fhr_kat_expiry(pim, up);
23fc858a 1322 if (PIM_DEBUG_PIM_TRACE)
996c9314
LB
1323 zlog_debug(
1324 "kat expired on %s[%s]; remove stream reference",
1325 up->sg_str, pim->vrf->name);
d62a17ae 1326 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
e3e532dd 1327
1328 /* Return if upstream entry got deleted.*/
1329 if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
1330 return NULL;
1331 }
02434c43
DS
1332 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1333 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1334
1335 if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
1336 return NULL;
1337 }
1338
e3e532dd 1339 /* upstream reference would have been added to track the local
1340 * membership if it is LHR. We have to clear it when KAT expires.
1341 * Otherwise would result in stale entry with uncleared ref count.
1342 */
1343 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
8022df6a
DS
1344 struct pim_upstream *parent = up->parent;
1345
d62a17ae 1346 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
ff459c36 1347 up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
8022df6a
DS
1348
1349 if (parent) {
996c9314
LB
1350 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1351 true);
8022df6a 1352 }
d62a17ae 1353 }
1354
ff459c36
AK
1355 return up;
1356}
1357static int pim_upstream_keep_alive_timer(struct thread *t)
1358{
1359 struct pim_upstream *up;
1360
1361 up = THREAD_ARG(t);
1362
1363 pim_upstream_keep_alive_timer_proc(up);
d62a17ae 1364 return 0;
f14248dd
DS
1365}
1366
d62a17ae 1367void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
f14248dd 1368{
d62a17ae 1369 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 1370 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1371 zlog_debug("kat start on %s with no stream reference",
1372 up->sg_str);
1373 }
1374 THREAD_OFF(up->t_ka_timer);
36417fcc
DS
1375 thread_add_timer(router->master, pim_upstream_keep_alive_timer, up,
1376 time, &up->t_ka_timer);
d62a17ae 1377
1378 /* any time keepalive is started against a SG we will have to
1379 * re-evaluate our active source database */
1380 pim_msdp_sa_local_update(up);
a53a9b3e
AK
1381 /* JoinDesired can change when KAT is started or stopped */
1382 pim_upstream_update_join_desired(up->pim, up);
1bf16443 1383}
1384
1385/* MSDP on RP needs to know if a source is registerable to this RP */
d62a17ae 1386static int pim_upstream_msdp_reg_timer(struct thread *t)
1bf16443 1387{
472ad383
DS
1388 struct pim_upstream *up = THREAD_ARG(t);
1389 struct pim_instance *pim = up->channel_oil->pim;
1bf16443 1390
d62a17ae 1391 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1392 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1393 return 1;
1bf16443 1394}
d62a17ae 1395void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1bf16443 1396{
d62a17ae 1397 THREAD_OFF(up->t_msdp_reg_timer);
36417fcc 1398 thread_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
d62a17ae 1399 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1bf16443 1400
d62a17ae 1401 pim_msdp_sa_local_update(up);
f14248dd 1402}
cb40b272
DS
1403
1404/*
1405 * 4.2.1 Last-Hop Switchover to the SPT
1406 *
1407 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1408 * RP. Once traffic from sources to joined groups arrives at a last-hop
1409 * router, it has the option of switching to receive the traffic on a
1410 * shortest path tree (SPT).
1411 *
1412 * The decision for a router to switch to the SPT is controlled as
1413 * follows:
1414 *
1415 * void
1416 * CheckSwitchToSpt(S,G) {
1417 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1418 * (+) pim_include(S,G) != NULL )
1419 * AND SwitchToSptDesired(S,G) ) {
1420 * # Note: Restarting the KAT will result in the SPT switch
1421 * set KeepaliveTimer(S,G) to Keepalive_Period
1422 * }
1423 * }
1424 *
1425 * SwitchToSptDesired(S,G) is a policy function that is implementation
1426 * defined. An "infinite threshold" policy can be implemented by making
1427 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1428 * first packet" policy can be implemented by making
1429 * SwitchToSptDesired(S,G) return true once a single packet has been
1430 * received for the source and group.
1431 */
8e5f97e3
DS
1432int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
1433 struct prefix_sg *sg)
cb40b272 1434{
8e5f97e3 1435 if (I_am_RP(pim, sg->grp))
d62a17ae 1436 return 1;
a3b58b4a 1437
d62a17ae 1438 return 0;
cb40b272 1439}
d7259eac 1440
d62a17ae 1441int pim_upstream_is_sg_rpt(struct pim_upstream *up)
80d9c3a0 1442{
d62a17ae 1443 struct listnode *chnode;
1444 struct pim_ifchannel *ch;
f21597f0 1445
d62a17ae 1446 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1447 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1448 return 1;
1449 }
e43b8697 1450
d62a17ae 1451 return 0;
80d9c3a0 1452}
3a66b17b
DS
1453/*
1454 * After receiving a packet set SPTbit:
1455 * void
1456 * Update_SPTbit(S,G,iif) {
1457 * if ( iif == RPF_interface(S)
2951a7a4
QY
1458 * AND JoinDesired(S,G) == true
1459 * AND ( DirectlyConnected(S) == true
3a66b17b
DS
1460 * OR RPF_interface(S) != RPF_interface(RP(G))
1461 * OR inherited_olist(S,G,rpt) == NULL
1462 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1463 * ( RPF'(S,G) != NULL ) )
1464 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
2951a7a4 1465 * Set SPTbit(S,G) to true
3a66b17b
DS
1466 * }
1467 * }
1468 */
d62a17ae 1469void pim_upstream_set_sptbit(struct pim_upstream *up,
1470 struct interface *incoming)
3a66b17b 1471{
d62a17ae 1472 struct pim_upstream *starup = up->parent;
1473
1474 // iif == RPF_interfvace(S)
1475 if (up->rpf.source_nexthop.interface != incoming) {
23fc858a 1476 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1477 zlog_debug(
1478 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1479 __PRETTY_FUNCTION__, incoming->name,
1480 up->rpf.source_nexthop.interface->name);
1481 return;
1482 }
1483
2951a7a4 1484 // AND JoinDesired(S,G) == true
6f0f014f 1485 if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) {
23fc858a 1486 if (PIM_DEBUG_PIM_TRACE)
6f0f014f
DS
1487 zlog_debug("%s: %s Join is not Desired",
1488 __PRETTY_FUNCTION__, up->sg_str);
1489 return;
1490 }
d62a17ae 1491
2951a7a4 1492 // DirectlyConnected(S) == true
d62a17ae 1493 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1494 up->sg.src)) {
23fc858a 1495 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1496 zlog_debug("%s: %s is directly connected to the source",
1497 __PRETTY_FUNCTION__, up->sg_str);
1498 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1499 return;
1500 }
1501
1502 // OR RPF_interface(S) != RPF_interface(RP(G))
1503 if (!starup
1504 || up->rpf.source_nexthop
1505 .interface != starup->rpf.source_nexthop.interface) {
2de05c60
DS
1506 struct pim_upstream *starup = up->parent;
1507
23fc858a 1508 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1509 zlog_debug(
1510 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1511 __PRETTY_FUNCTION__, up->sg_str);
1512 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
2de05c60
DS
1513
1514 pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
d62a17ae 1515 return;
1516 }
1517
1518 // OR inherited_olist(S,G,rpt) == NULL
1519 if (pim_upstream_is_sg_rpt(up)
1520 && pim_upstream_empty_inherited_olist(up)) {
23fc858a 1521 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1522 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1523 __PRETTY_FUNCTION__, up->sg_str);
1524 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1525 return;
1526 }
1527
1528 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1529 // ( RPF'(S,G) != NULL ) )
1530 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
23fc858a 1531 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1532 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1533 __PRETTY_FUNCTION__, up->sg_str);
1534 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1535 return;
1536 }
1537
1538 return;
3a66b17b 1539}
80d9c3a0 1540
d62a17ae 1541const char *pim_upstream_state2str(enum pim_upstream_state join_state)
d7259eac 1542{
d62a17ae 1543 switch (join_state) {
1544 case PIM_UPSTREAM_NOTJOINED:
1545 return "NotJoined";
1546 break;
1547 case PIM_UPSTREAM_JOINED:
1548 return "Joined";
1549 break;
1550 }
1551 return "Unknown";
d7259eac 1552}
627ed2a3 1553
c35b7e6b
QY
1554const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
1555 size_t state_str_len)
e0e127b0 1556{
d62a17ae 1557 switch (reg_state) {
1558 case PIM_REG_NOINFO:
c35b7e6b 1559 strlcpy(state_str, "RegNoInfo", state_str_len);
d62a17ae 1560 break;
1561 case PIM_REG_JOIN:
c35b7e6b 1562 strlcpy(state_str, "RegJoined", state_str_len);
d62a17ae 1563 break;
1564 case PIM_REG_JOIN_PENDING:
c35b7e6b 1565 strlcpy(state_str, "RegJoinPend", state_str_len);
d62a17ae 1566 break;
1567 case PIM_REG_PRUNE:
c35b7e6b 1568 strlcpy(state_str, "RegPrune", state_str_len);
d62a17ae 1569 break;
1570 default:
c35b7e6b 1571 strlcpy(state_str, "RegUnknown", state_str_len);
d62a17ae 1572 }
1573 return state_str;
e0e127b0 1574}
1575
d62a17ae 1576static int pim_upstream_register_stop_timer(struct thread *t)
627ed2a3 1577{
d62a17ae 1578 struct pim_interface *pim_ifp;
8e5f97e3 1579 struct pim_instance *pim;
d62a17ae 1580 struct pim_upstream *up;
d62a17ae 1581 up = THREAD_ARG(t);
8e5f97e3 1582 pim = up->channel_oil->pim;
d62a17ae 1583
23fc858a 1584 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1585 char state_str[PIM_REG_STATE_STR_LEN];
8dbdb215
DS
1586 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1587 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
c35b7e6b 1588 pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
d62a17ae 1589 }
1590
1591 switch (up->reg_state) {
1592 case PIM_REG_JOIN_PENDING:
1593 up->reg_state = PIM_REG_JOIN;
8e5f97e3 1594 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
1595 PIM_OIF_FLAG_PROTO_PIM,
1596 __func__);
2951a7a4 1597 pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
d62a17ae 1598 break;
1599 case PIM_REG_JOIN:
1600 break;
1601 case PIM_REG_PRUNE:
957d93ea 1602 if (!up->rpf.source_nexthop.interface) {
23fc858a 1603 if (PIM_DEBUG_PIM_TRACE)
957d93ea
SP
1604 zlog_debug("%s: up %s RPF is not present",
1605 __PRETTY_FUNCTION__, up->sg_str);
1606 return 0;
1607 }
1608
d62a17ae 1609 pim_ifp = up->rpf.source_nexthop.interface->info;
1610 if (!pim_ifp) {
23fc858a 1611 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1612 zlog_debug(
1613 "%s: Interface: %s is not configured for pim",
1614 __PRETTY_FUNCTION__,
1615 up->rpf.source_nexthop.interface->name);
1616 return 0;
1617 }
1618 up->reg_state = PIM_REG_JOIN_PENDING;
1619 pim_upstream_start_register_stop_timer(up, 1);
1620
1621 if (((up->channel_oil->cc.lastused / 100)
2f5b0028 1622 > pim->keep_alive_time)
d9c9a9ee 1623 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
23fc858a 1624 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1625 zlog_debug(
1626 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1627 __PRETTY_FUNCTION__);
1628 return 0;
1629 }
aea1f845 1630 pim_null_register_send(up);
d62a17ae 1631 break;
1632 default:
1633 break;
70e7fda8 1634 }
d62a17ae 1635
1636 return 0;
627ed2a3
DS
1637}
1638
d62a17ae 1639void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1640 int null_register)
627ed2a3 1641{
d62a17ae 1642 uint32_t time;
1643
1644 THREAD_TIMER_OFF(up->t_rs_timer);
1645
1646 if (!null_register) {
1647 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1648 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1649 time = lower + (random() % (upper - lower + 1))
1650 - PIM_REGISTER_PROBE_PERIOD;
1651 } else
1652 time = PIM_REGISTER_PROBE_PERIOD;
1653
23fc858a 1654 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1655 zlog_debug(
1656 "%s: (S,G)=%s Starting upstream register stop timer %d",
1657 __PRETTY_FUNCTION__, up->sg_str, time);
1658 }
36417fcc
DS
1659 thread_add_timer(router->master, pim_upstream_register_stop_timer, up,
1660 time, &up->t_rs_timer);
627ed2a3 1661}
4fdc8f36 1662
9b29ea95
DS
1663int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1664 struct pim_upstream *up)
4fdc8f36 1665{
d62a17ae 1666 struct interface *ifp;
d62a17ae 1667 struct pim_ifchannel *ch, *starch;
d62a17ae 1668 struct pim_upstream *starup = up->parent;
1669 int output_intf = 0;
1670
46dd6edb 1671 if (!up->rpf.source_nexthop.interface)
23fc858a 1672 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1673 zlog_debug("%s: up %s RPF is not present",
1674 __PRETTY_FUNCTION__, up->sg_str);
d62a17ae 1675
451fda4f 1676 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1677 if (!ifp->info)
1678 continue;
1679
1680 ch = pim_ifchannel_find(ifp, &up->sg);
1681
1682 if (starup)
1683 starch = pim_ifchannel_find(ifp, &starup->sg);
1684 else
1685 starch = NULL;
1686
1687 if (!ch && !starch)
1688 continue;
1689
1690 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1691 starch)) {
1692 int flag = PIM_OIF_FLAG_PROTO_PIM;
1693
1694 if (!ch)
1695 flag = PIM_OIF_FLAG_PROTO_STAR;
1696
1b249e70
AK
1697 pim_channel_add_oif(up->channel_oil, ifp, flag,
1698 __func__);
d62a17ae 1699 output_intf++;
1700 }
1701 }
1702
1703 return output_intf;
b5183fd1
DS
1704}
1705
1706/*
1707 * For a given upstream, determine the inherited_olist
1708 * and apply it.
1709 *
1710 * inherited_olist(S,G,rpt) =
1711 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1712 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1713 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1714 *
1715 * inherited_olist(S,G) =
1716 * inherited_olist(S,G,rpt) (+)
1717 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1718 *
1719 * return 1 if there are any output interfaces
1720 * return 0 if there are not any output interfaces
1721 */
9b29ea95
DS
1722int pim_upstream_inherited_olist(struct pim_instance *pim,
1723 struct pim_upstream *up)
b5183fd1 1724{
9b29ea95 1725 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1726
1727 /*
1728 * If we have output_intf switch state to Join and work like normal
1729 * If we don't have an output_intf that means we are probably a
1730 * switch on a stick so turn on forwarding to just accept the
1731 * incoming packets so we don't bother the other stuff!
1732 */
a53a9b3e
AK
1733 pim_upstream_update_join_desired(pim, up);
1734
1735 if (!output_intf)
d62a17ae 1736 forward_on(up);
1737
1738 return output_intf;
4fdc8f36 1739}
d3dd1804 1740
d62a17ae 1741int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
80d9c3a0 1742{
d62a17ae 1743 return pim_channel_oil_empty(up->channel_oil);
80d9c3a0
DS
1744}
1745
d3dd1804
DS
1746/*
1747 * When we have a new neighbor,
1748 * find upstreams that don't have their rpf_addr
1749 * set and see if the new neighbor allows
1750 * the join to be sent
1751 */
9b29ea95 1752void pim_upstream_find_new_rpf(struct pim_instance *pim)
d3dd1804 1753{
d62a17ae 1754 struct listnode *up_node;
1755 struct listnode *up_nextnode;
1756 struct pim_upstream *up;
1757
1758 /*
1759 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1760 */
9b29ea95 1761 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
957d93ea 1762 if (up->upstream_addr.s_addr == INADDR_ANY) {
23fc858a 1763 if (PIM_DEBUG_PIM_TRACE)
957d93ea
SP
1764 zlog_debug(
1765 "%s: RP not configured for Upstream %s",
1766 __PRETTY_FUNCTION__, up->sg_str);
1767 continue;
1768 }
1769
d62a17ae 1770 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
23fc858a 1771 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1772 zlog_debug(
957d93ea
SP
1773 "%s: Upstream %s without a path to send join, checking",
1774 __PRETTY_FUNCTION__, up->sg_str);
ae14da48 1775 pim_rpf_update(pim, up, NULL);
d62a17ae 1776 }
d3dd1804 1777 }
d3dd1804 1778}
0f588989 1779
d8b87afe 1780unsigned int pim_upstream_hash_key(const void *arg)
0f588989 1781{
d8b87afe 1782 const struct pim_upstream *up = arg;
0f588989 1783
d62a17ae 1784 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
0f588989
DS
1785}
1786
9b29ea95 1787void pim_upstream_terminate(struct pim_instance *pim)
0f588989 1788{
172e45dc
DS
1789 struct pim_upstream *up;
1790
1791 if (pim->upstream_list) {
1d483838
DS
1792 while (pim->upstream_list->count) {
1793 up = listnode_head(pim->upstream_list);
172e45dc 1794 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1d483838 1795 }
172e45dc 1796
6a154c88 1797 list_delete(&pim->upstream_list);
172e45dc 1798 }
0f588989 1799
9b29ea95
DS
1800 if (pim->upstream_hash)
1801 hash_free(pim->upstream_hash);
1802 pim->upstream_hash = NULL;
0c68972d
DS
1803
1804 if (pim->upstream_sg_wheel)
1805 wheel_delete(pim->upstream_sg_wheel);
1806 pim->upstream_sg_wheel = NULL;
0f588989
DS
1807}
1808
74df8d6d 1809bool pim_upstream_equal(const void *arg1, const void *arg2)
0f588989 1810{
d62a17ae 1811 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1812 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
0f588989 1813
d62a17ae 1814 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1815 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
74df8d6d 1816 return true;
0f588989 1817
74df8d6d 1818 return false;
0f588989
DS
1819}
1820
1bf16443 1821/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1822 * the cases where kat has to be restarted on rxing traffic -
1823 *
2951a7a4 1824 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1bf16443 1825 * set KeepaliveTimer(S,G) to Keepalive_Period
1826 * # Note: a register state transition or UpstreamJPState(S,G)
1827 * # transition may happen as a result of restarting
1828 * # KeepaliveTimer, and must be dealt with here.
1829 * }
1830 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1831 * inherited_olist(S,G) != NULL ) {
1832 * set KeepaliveTimer(S,G) to Keepalive_Period
1833 * }
1834 */
1835static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1836{
8e5f97e3
DS
1837 struct pim_instance *pim = up->channel_oil->pim;
1838
d62a17ae 1839 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1840 * so we will skip that here */
957d93ea
SP
1841 if (up->rpf.source_nexthop.interface &&
1842 pim_if_connected_to_source(up->rpf.source_nexthop.interface,
d62a17ae 1843 up->sg.src)) {
1844 return true;
1845 }
1846
1847 if ((up->join_state == PIM_UPSTREAM_JOINED)
1848 && !pim_upstream_empty_inherited_olist(up)) {
1849 /* XXX: I have added this RP check just for 3.2 and it's a
1850 * digression from
1851 * what rfc-4601 says. Till now we were only running KAT on FHR
1852 * and RP and
1853 * there is some angst around making the change to run it all
1854 * routers that
1855 * maintain the (S, G) state. This is tracked via CM-13601 and
1856 * MUST be
1857 * removed to handle spt turn-arounds correctly in a 3-tier clos
1858 */
8e5f97e3 1859 if (I_am_RP(pim, up->sg.grp))
d62a17ae 1860 return true;
1861 }
1862
1863 return false;
1bf16443 1864}
1865
9c5e4d62
DS
1866/*
1867 * Code to check and see if we've received packets on a S,G mroute
1868 * and if so to set the SPT bit appropriately
1869 */
d62a17ae 1870static void pim_upstream_sg_running(void *arg)
9c5e4d62 1871{
d62a17ae 1872 struct pim_upstream *up = (struct pim_upstream *)arg;
8e5f97e3 1873 struct pim_instance *pim = up->channel_oil->pim;
d62a17ae 1874
1875 // No packet can have arrived here if this is the case
8e5f97e3 1876 if (!up->channel_oil->installed) {
23fc858a 1877 if (PIM_DEBUG_PIM_TRACE)
41714081 1878 zlog_debug("%s: %s%s is not installed in mroute",
996c9314
LB
1879 __PRETTY_FUNCTION__, up->sg_str,
1880 pim->vrf->name);
d62a17ae 1881 return;
1882 }
1883
1884 /*
1885 * This is a bit of a hack
1886 * We've noted that we should rescan but
1887 * we've missed the window for doing so in
1888 * pim_zebra.c for some reason. I am
1889 * only doing this at this point in time
1890 * to get us up and working for the moment
1891 */
1892 if (up->channel_oil->oil_inherited_rescan) {
23fc858a 1893 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1894 zlog_debug(
8dbdb215 1895 "%s: Handling unscanned inherited_olist for %s[%s]",
996c9314
LB
1896 __PRETTY_FUNCTION__, up->sg_str,
1897 pim->vrf->name);
8e5f97e3 1898 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1899 up->channel_oil->oil_inherited_rescan = 0;
1900 }
1901 pim_mroute_update_counters(up->channel_oil);
1902
1903 // Have we seen packets?
1904 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1905 && (up->channel_oil->cc.lastused / 100 > 30)) {
23fc858a 1906 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1907 zlog_debug(
8dbdb215
DS
1908 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1909 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1910 up->channel_oil->cc.oldpktcnt,
1911 up->channel_oil->cc.pktcnt,
1912 up->channel_oil->cc.lastused / 100);
1913 }
1914 return;
e43b8697 1915 }
d62a17ae 1916
1917 if (pim_upstream_kat_start_ok(up)) {
1918 /* Add a source reference to the stream if
1919 * one doesn't already exist */
1920 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 1921 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1922 zlog_debug(
8dbdb215
DS
1923 "source reference created on kat restart %s[%s]",
1924 up->sg_str, pim->vrf->name);
d62a17ae 1925
1926 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1927 __PRETTY_FUNCTION__);
1928 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1929 pim_upstream_fhr_kat_start(up);
1930 }
19b807ca 1931 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1932 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
19b807ca 1933 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1934
957d93ea
SP
1935 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
1936 (up->rpf.source_nexthop.interface)) {
d62a17ae 1937 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
850a9f99 1938 }
d62a17ae 1939 return;
9c5e4d62
DS
1940}
1941
9b29ea95 1942void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
a7b2b1e2 1943{
d62a17ae 1944 struct pim_upstream *up;
1945 struct listnode *node;
a7b2b1e2 1946
9b29ea95 1947 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1948 if (up->sg.src.s_addr != INADDR_ANY)
1949 continue;
a7b2b1e2 1950
d62a17ae 1951 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1952 continue;
a7b2b1e2 1953
9b29ea95 1954 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70 1955 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 1956 }
a7b2b1e2
DS
1957}
1958
9b29ea95
DS
1959void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
1960 struct prefix_list *pl)
df94f9a9 1961{
d62a17ae 1962 const char *pname = prefix_list_name(pl);
df94f9a9 1963
9b29ea95
DS
1964 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
1965 pim_upstream_remove_lhr_star_pimreg(pim, pname);
d62a17ae 1966 }
df94f9a9
DS
1967}
1968
1969/*
1970 * nlist -> The new prefix list
1971 *
1972 * Per Group Application of pimreg to the OIL
1973 * If the prefix list tells us DENY then
1974 * we need to Switchover to SPT immediate
1975 * so add the pimreg.
1976 * If the prefix list tells us to ACCEPT than
1977 * we need to Never do the SPT so remove
1978 * the interface
1979 *
1980 */
9b29ea95
DS
1981void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
1982 const char *nlist)
a7b2b1e2 1983{
d62a17ae 1984 struct pim_upstream *up;
1985 struct listnode *node;
1986 struct prefix_list *np;
1987 struct prefix g;
1988 enum prefix_list_type apply_new;
1989
1990 np = prefix_list_lookup(AFI_IP, nlist);
1991
1992 g.family = AF_INET;
1993 g.prefixlen = IPV4_MAX_PREFIXLEN;
1994
9b29ea95 1995 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1996 if (up->sg.src.s_addr != INADDR_ANY)
1997 continue;
1998
1999 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
2000 continue;
2001
2002 if (!nlist) {
9b29ea95 2003 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 2004 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 2005 continue;
2006 }
2007 g.u.prefix4 = up->sg.grp;
2008 apply_new = prefix_list_apply(np, &g);
2009 if (apply_new == PREFIX_DENY)
9b29ea95 2010 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
2011 PIM_OIF_FLAG_PROTO_IGMP,
2012 __func__);
d62a17ae 2013 else
9b29ea95 2014 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 2015 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 2016 }
a7b2b1e2
DS
2017}
2018
9b29ea95 2019void pim_upstream_init(struct pim_instance *pim)
0f588989 2020{
c2cfa843 2021 char name[64];
9fb302f4 2022
c2cfa843
DS
2023 snprintf(name, 64, "PIM %s Timer Wheel",
2024 pim->vrf->name);
9b29ea95 2025 pim->upstream_sg_wheel =
36417fcc 2026 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
c2cfa843 2027 pim_upstream_sg_running, name);
9fb302f4 2028
c2cfa843
DS
2029 snprintf(name, 64, "PIM %s Upstream Hash",
2030 pim->vrf->name);
9b29ea95 2031 pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
c2cfa843 2032 pim_upstream_equal, name);
d62a17ae 2033
9b29ea95 2034 pim->upstream_list = list_new();
9b29ea95 2035 pim->upstream_list->cmp = pim_upstream_compare;
0f588989 2036}