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