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