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