]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
Merge pull request #5498 from mjstapp/sharp_with_labels
[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
SP
886 if (up->rpf.source_nexthop.interface) {
887 pim_ifp = up->rpf.source_nexthop.interface->info;
35d6862d
AK
888 pim_upstream_mroute_iif_update(up->channel_oil,
889 __func__);
732c209c 890 }
d62a17ae 891 }
892
9b29ea95 893 listnode_add_sort(pim->upstream_list, up);
d62a17ae 894
23fc858a 895 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 896 zlog_debug(
897 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
898 __PRETTY_FUNCTION__, up->sg_str,
899 inet_ntoa(up->upstream_addr), up->ref_count);
900 }
901
902 return up;
12e41d03
DL
903}
904
9b29ea95
DS
905struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
906 struct prefix_sg *sg)
12e41d03 907{
d62a17ae 908 struct pim_upstream lookup;
909 struct pim_upstream *up = NULL;
12e41d03 910
d62a17ae 911 lookup.sg = *sg;
9b29ea95 912 up = hash_lookup(pim->upstream_hash, &lookup);
d62a17ae 913 return up;
12e41d03
DL
914}
915
d62a17ae 916struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
69e3538c
AK
917 struct interface *incoming,
918 int flags, const char *name)
e711cd3c 919{
69e3538c 920 struct pim_interface *pim_ifp = incoming->info;
d62a17ae 921
69e3538c
AK
922 return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
923 NULL));
e711cd3c
DS
924}
925
d62a17ae 926void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1bf16443 927{
69e3538c
AK
928 /* when we go from non-FHR to FHR we need to re-eval traffic
929 * forwarding path
930 */
931 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
932 PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
933 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
934 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
935 }
936
41a115e4
AK
937 /* re-eval joinDesired; clearing peer-msdp-sa flag can
938 * cause JD to change
939 */
940 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags) &&
941 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags)) {
942 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up->flags);
943 pim_upstream_update_join_desired(up->pim, up);
944 }
945
d62a17ae 946 up->flags |= flags;
947 ++up->ref_count;
23fc858a 948 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 949 zlog_debug("%s(%s): upstream %s ref count %d increment",
950 __PRETTY_FUNCTION__, name, up->sg_str,
951 up->ref_count);
1bf16443 952}
953
2002dcdb
DS
954struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
955 struct prefix_sg *sg,
d62a17ae 956 struct interface *incoming, int flags,
0885a9f1
DS
957 const char *name,
958 struct pim_ifchannel *ch)
12e41d03 959{
d62a17ae 960 struct pim_upstream *up = NULL;
961 int found = 0;
9b29ea95 962
2002dcdb 963 up = pim_upstream_find(pim, sg);
d62a17ae 964 if (up) {
965 pim_upstream_ref(up, flags, name);
966 found = 1;
967 } else {
0885a9f1 968 up = pim_upstream_new(pim, sg, incoming, flags, ch);
d62a17ae 969 }
970
23fc858a 971 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 972 if (up) {
973 char buf[PREFIX2STR_BUFFER];
974 prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf));
975 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
f4075cb4 976 __PRETTY_FUNCTION__, name,
55785900 977 up->sg_str, buf, up->rpf.source_nexthop.interface ?
957d93ea 978 up->rpf.source_nexthop.interface->name : "Unknown" ,
55785900 979 found, up->ref_count);
d62a17ae 980 } else
981 zlog_debug("%s(%s): (%s) failure to create",
982 __PRETTY_FUNCTION__, name,
983 pim_str_sg_dump(sg));
984 }
12e41d03 985
d62a17ae 986 return up;
12e41d03
DL
987}
988
a53a9b3e
AK
989/*
990 * Passed in up must be the upstream for ch. starch is NULL if no
991 * information
992 * This function is copied over from
993 * pim_upstream_evaluate_join_desired_interface but limited to
994 * parent (*,G)'s includes/joins.
995 */
996int pim_upstream_eval_inherit_if(struct pim_upstream *up,
997 struct pim_ifchannel *ch,
998 struct pim_ifchannel *starch)
999{
1000 /* if there is an explicit prune for this interface we cannot
1001 * add it to the OIL
1002 */
1003 if (ch) {
1004 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1005 return 0;
1006 }
1007
1008 /* Check if the OIF can be inherited fron the (*,G) entry
1009 */
1010 if (starch) {
1011 if (!pim_macro_ch_lost_assert(starch)
1012 && pim_macro_chisin_joins_or_include(starch))
1013 return 1;
1014 }
1015
1016 return 0;
1017}
1018
c8fc07cb
DS
1019/*
1020 * Passed in up must be the upstream for ch. starch is NULL if no
1021 * information
1022 */
d62a17ae 1023int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
1024 struct pim_ifchannel *ch,
1025 struct pim_ifchannel *starch)
7a3ddda5 1026{
d62a17ae 1027 if (ch) {
1028 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1029 return 0;
1030
1031 if (!pim_macro_ch_lost_assert(ch)
1032 && pim_macro_chisin_joins_or_include(ch))
1033 return 1;
1034 }
1035
1036 /*
1037 * joins (*,G)
1038 */
1039 if (starch) {
a53a9b3e
AK
1040 /* XXX: check on this with donald
1041 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1042 * upstream flags?
1043 */
1044#if 0
d62a17ae 1045 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1046 return 0;
a53a9b3e 1047#endif
d62a17ae 1048
1049 if (!pim_macro_ch_lost_assert(starch)
1050 && pim_macro_chisin_joins_or_include(starch))
1051 return 1;
1052 }
1053
1054 return 0;
7a3ddda5
DS
1055}
1056
a53a9b3e
AK
1057/* Returns true if immediate OIL is empty and is used to evaluate
1058 * JoinDesired. See pim_upstream_evaluate_join_desired.
12e41d03 1059 */
a53a9b3e 1060static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
9b29ea95 1061 struct pim_upstream *up)
12e41d03 1062{
d62a17ae 1063 struct interface *ifp;
a53a9b3e 1064 struct pim_ifchannel *ch;
12e41d03 1065
451fda4f 1066 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1067 if (!ifp->info)
1068 continue;
c8fc07cb 1069
d62a17ae 1070 ch = pim_ifchannel_find(ifp, &up->sg);
a53a9b3e 1071 if (!ch)
d62a17ae 1072 continue;
12e41d03 1073
a53a9b3e
AK
1074 /* If we have even one immediate OIF we can return with
1075 * not-empty
1076 */
1077 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1078 NULL /* starch */))
1079 return false;
d62a17ae 1080 } /* scan iface channel list */
12e41d03 1081
a53a9b3e
AK
1082 /* immediate_oil is empty */
1083 return true;
1084}
1085
41a115e4
AK
1086
1087static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1088{
1089 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1090}
1091
a53a9b3e
AK
1092/*
1093 * bool JoinDesired(*,G) {
1094 * if (immediate_olist(*,G) != NULL)
1095 * return TRUE
1096 * else
1097 * return FALSE
1098 * }
1099 *
1100 * bool JoinDesired(S,G) {
1101 * return( immediate_olist(S,G) != NULL
1102 * OR ( KeepaliveTimer(S,G) is running
1103 * AND inherited_olist(S,G) != NULL ) )
1104 * }
1105 */
1106int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
1107 struct pim_upstream *up)
1108{
1109 bool empty_imm_oil;
1110 bool empty_inh_oil;
1111
1112 empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1113
1114 /* (*,G) */
1115 if (up->sg.src.s_addr == INADDR_ANY)
1116 return !empty_imm_oil;
1117
1118 /* (S,G) */
1119 if (!empty_imm_oil)
1120 return true;
1121 empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1122 if (!empty_inh_oil &&
1123 (pim_upstream_is_kat_running(up) ||
41a115e4 1124 pim_upstream_is_msdp_peer_sa(up)))
a53a9b3e
AK
1125 return true;
1126
1127 return false;
12e41d03
DL
1128}
1129
1130/*
1131 See also pim_upstream_evaluate_join_desired() above.
1132*/
9b29ea95
DS
1133void pim_upstream_update_join_desired(struct pim_instance *pim,
1134 struct pim_upstream *up)
12e41d03 1135{
d62a17ae 1136 int was_join_desired; /* boolean */
1137 int is_join_desired; /* boolean */
1138
1139 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1140
9b29ea95 1141 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
d62a17ae 1142 if (is_join_desired)
1143 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1144 else
1145 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1146
1147 /* switched from false to true */
47e3ce59 1148 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1eca8576 1149 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
d62a17ae 1150 return;
1151 }
1152
1153 /* switched from true to false */
1154 if (!is_join_desired && was_join_desired) {
1eca8576 1155 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
d62a17ae 1156 return;
1157 }
12e41d03
DL
1158}
1159
1160/*
1161 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1162 Transitions from Joined State
1163 RPF'(S,G) GenID changes
1164
1165 The upstream (S,G) state machine remains in Joined state. If the
1166 Join Timer is set to expire in more than t_override seconds, reset
1167 it so that it expires after t_override seconds.
1168*/
9b29ea95
DS
1169void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
1170 struct in_addr neigh_addr)
12e41d03 1171{
d62a17ae 1172 struct listnode *up_node;
1173 struct listnode *up_nextnode;
1174 struct pim_upstream *up;
1175
1176 /*
1177 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1178 */
9b29ea95 1179 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
d62a17ae 1180
23fc858a 1181 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1182 char neigh_str[INET_ADDRSTRLEN];
1183 char rpf_addr_str[PREFIX_STRLEN];
1184 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
1185 sizeof(neigh_str));
1186 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
1187 sizeof(rpf_addr_str));
1188 zlog_debug(
8dbdb215 1189 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
996c9314
LB
1190 __PRETTY_FUNCTION__, neigh_str, up->sg_str,
1191 pim->vrf->name,
d62a17ae 1192 up->join_state == PIM_UPSTREAM_JOINED,
1193 rpf_addr_str);
1194 }
1195
1196 /* consider only (S,G) upstream in Joined state */
1197 if (up->join_state != PIM_UPSTREAM_JOINED)
1198 continue;
1199
1200 /* match RPF'(S,G)=neigh_addr */
1201 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
1202 continue;
1203
1204 pim_upstream_join_timer_decrease_to_t_override(
1205 "RPF'(S,G) GenID change", up);
1206 }
12e41d03
DL
1207}
1208
1209
1210void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1211 struct interface *old_rpf_ifp)
1212{
d62a17ae 1213 struct listnode *chnode;
1214 struct listnode *chnextnode;
1215 struct pim_ifchannel *ch;
1216
1217 /* search all ifchannels */
1218 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1219 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1220 if (
1221 /* RPF_interface(S) was NOT I */
1222 (old_rpf_ifp == ch->interface) &&
1223 /* RPF_interface(S) stopped being I */
1224 (ch->upstream->rpf.source_nexthop
957d93ea
SP
1225 .interface) &&
1226 (ch->upstream->rpf.source_nexthop
1227 .interface != ch->interface)) {
d62a17ae 1228 assert_action_a5(ch);
1229 }
1230 } /* PIM_IFASSERT_I_AM_LOSER */
1231
1232 pim_ifchannel_update_assert_tracking_desired(ch);
1233 }
12e41d03
DL
1234}
1235
1236void pim_upstream_update_could_assert(struct pim_upstream *up)
1237{
d62a17ae 1238 struct listnode *chnode;
1239 struct listnode *chnextnode;
1240 struct pim_ifchannel *ch;
1241
1242 /* scan per-interface (S,G) state */
1243 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1244 pim_ifchannel_update_could_assert(ch);
1245 } /* scan iface channel list */
12e41d03
DL
1246}
1247
1248void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1249{
d62a17ae 1250 struct listnode *chnode;
1251 struct listnode *chnextnode;
1252 struct pim_ifchannel *ch;
12e41d03 1253
d62a17ae 1254 /* scan per-interface (S,G) state */
1255 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1256 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 1257
d62a17ae 1258 } /* scan iface channel list */
12e41d03
DL
1259}
1260
1261static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1262{
d62a17ae 1263 struct listnode *chnode;
1264 struct listnode *chnextnode;
1265 struct pim_interface *pim_ifp;
1266 struct pim_ifchannel *ch;
1267
1268 /* scan per-interface (S,G) state */
1269 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1270 if (!ch->interface)
1271 continue;
1272 pim_ifp = ch->interface->info;
1273 if (!pim_ifp)
1274 continue;
1275
1276 pim_ifchannel_update_assert_tracking_desired(ch);
1277
1278 } /* scan iface channel list */
12e41d03 1279}
f14248dd 1280
1bf16443 1281/* When kat is stopped CouldRegister goes to false so we need to
1282 * transition the (S, G) on FHR to NI state and remove reg tunnel
1283 * from the OIL */
9b29ea95
DS
1284static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1285 struct pim_upstream *up)
1bf16443 1286{
d62a17ae 1287 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1288 return;
1289
23fc858a 1290 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1291 zlog_debug("kat expired on %s; clear fhr reg state",
1292 up->sg_str);
1293
1294 /* stop reg-stop timer */
1295 THREAD_OFF(up->t_rs_timer);
1296 /* remove regiface from the OIL if it is there*/
9b29ea95 1297 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 1298 PIM_OIF_FLAG_PROTO_PIM, __func__);
d62a17ae 1299 /* clear the register state */
1300 up->reg_state = PIM_REG_NOINFO;
1301 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1bf16443 1302}
1303
1304/* When kat is started CouldRegister can go to true. And if it does we
1305 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1306 * to the OIL */
1307static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1308{
d62a17ae 1309 if (pim_upstream_could_register(up)) {
23fc858a 1310 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1311 zlog_debug(
1312 "kat started on %s; set fhr reg state to joined",
1313 up->sg_str);
1314
1315 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1316 if (up->reg_state == PIM_REG_NOINFO)
1317 pim_register_join(up);
69e3538c 1318 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
d62a17ae 1319 }
1bf16443 1320}
1321
f14248dd
DS
1322/*
1323 * On an RP, the PMBR value must be cleared when the
1324 * Keepalive Timer expires
1bf16443 1325 * KAT expiry indicates that flow is inactive. If the flow was created or
1326 * maintained by activity now is the time to deref it.
f14248dd 1327 */
ff459c36
AK
1328struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1329 struct pim_upstream *up)
f14248dd 1330{
8e5f97e3 1331 struct pim_instance *pim;
d62a17ae 1332
8e5f97e3 1333 pim = up->channel_oil->pim;
d62a17ae 1334
820b4a40
AK
1335 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
1336 /* if the router is a PIM vxlan encapsulator we prevent expiry
1337 * of KAT as the mroute is pre-setup without any traffic
1338 */
1339 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
ff459c36 1340 return up;
820b4a40
AK
1341 }
1342
8e5f97e3 1343 if (I_am_RP(pim, up->sg.grp)) {
d62a17ae 1344 pim_br_clear_pmbr(&up->sg);
1345 /*
1346 * We need to do more here :)
1347 * But this is the start.
1348 */
1349 }
1350
1351 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1352 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1353
a53a9b3e
AK
1354 /* JoinDesired can change when KAT is started or stopped */
1355 pim_upstream_update_join_desired(pim, up);
1356
d62a17ae 1357 /* if entry was created because of activity we need to deref it */
1358 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
8e5f97e3 1359 pim_upstream_fhr_kat_expiry(pim, up);
23fc858a 1360 if (PIM_DEBUG_PIM_TRACE)
996c9314
LB
1361 zlog_debug(
1362 "kat expired on %s[%s]; remove stream reference",
1363 up->sg_str, pim->vrf->name);
d62a17ae 1364 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
e3e532dd 1365
1366 /* Return if upstream entry got deleted.*/
1367 if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
1368 return NULL;
1369 }
02434c43
DS
1370 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1371 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1372
1373 if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
1374 return NULL;
1375 }
1376
e3e532dd 1377 /* upstream reference would have been added to track the local
1378 * membership if it is LHR. We have to clear it when KAT expires.
1379 * Otherwise would result in stale entry with uncleared ref count.
1380 */
1381 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
8022df6a
DS
1382 struct pim_upstream *parent = up->parent;
1383
d62a17ae 1384 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
ff459c36 1385 up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
8022df6a
DS
1386
1387 if (parent) {
996c9314
LB
1388 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1389 true);
8022df6a 1390 }
d62a17ae 1391 }
1392
ff459c36
AK
1393 return up;
1394}
1395static int pim_upstream_keep_alive_timer(struct thread *t)
1396{
1397 struct pim_upstream *up;
1398
1399 up = THREAD_ARG(t);
1400
1401 pim_upstream_keep_alive_timer_proc(up);
d62a17ae 1402 return 0;
f14248dd
DS
1403}
1404
d62a17ae 1405void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
f14248dd 1406{
d62a17ae 1407 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 1408 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1409 zlog_debug("kat start on %s with no stream reference",
1410 up->sg_str);
1411 }
1412 THREAD_OFF(up->t_ka_timer);
36417fcc
DS
1413 thread_add_timer(router->master, pim_upstream_keep_alive_timer, up,
1414 time, &up->t_ka_timer);
d62a17ae 1415
1416 /* any time keepalive is started against a SG we will have to
1417 * re-evaluate our active source database */
1418 pim_msdp_sa_local_update(up);
a53a9b3e
AK
1419 /* JoinDesired can change when KAT is started or stopped */
1420 pim_upstream_update_join_desired(up->pim, up);
1bf16443 1421}
1422
1423/* MSDP on RP needs to know if a source is registerable to this RP */
d62a17ae 1424static int pim_upstream_msdp_reg_timer(struct thread *t)
1bf16443 1425{
472ad383
DS
1426 struct pim_upstream *up = THREAD_ARG(t);
1427 struct pim_instance *pim = up->channel_oil->pim;
1bf16443 1428
d62a17ae 1429 /* source is no longer active - pull the SA from MSDP's cache */
472ad383 1430 pim_msdp_sa_local_del(pim, &up->sg);
d62a17ae 1431 return 1;
1bf16443 1432}
d62a17ae 1433void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1bf16443 1434{
d62a17ae 1435 THREAD_OFF(up->t_msdp_reg_timer);
36417fcc 1436 thread_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
d62a17ae 1437 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1bf16443 1438
d62a17ae 1439 pim_msdp_sa_local_update(up);
f14248dd 1440}
cb40b272
DS
1441
1442/*
1443 * 4.2.1 Last-Hop Switchover to the SPT
1444 *
1445 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1446 * RP. Once traffic from sources to joined groups arrives at a last-hop
1447 * router, it has the option of switching to receive the traffic on a
1448 * shortest path tree (SPT).
1449 *
1450 * The decision for a router to switch to the SPT is controlled as
1451 * follows:
1452 *
1453 * void
1454 * CheckSwitchToSpt(S,G) {
1455 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1456 * (+) pim_include(S,G) != NULL )
1457 * AND SwitchToSptDesired(S,G) ) {
1458 * # Note: Restarting the KAT will result in the SPT switch
1459 * set KeepaliveTimer(S,G) to Keepalive_Period
1460 * }
1461 * }
1462 *
1463 * SwitchToSptDesired(S,G) is a policy function that is implementation
1464 * defined. An "infinite threshold" policy can be implemented by making
1465 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1466 * first packet" policy can be implemented by making
1467 * SwitchToSptDesired(S,G) return true once a single packet has been
1468 * received for the source and group.
1469 */
2ef4ed70 1470int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim,
8e5f97e3 1471 struct prefix_sg *sg)
cb40b272 1472{
8e5f97e3 1473 if (I_am_RP(pim, sg->grp))
d62a17ae 1474 return 1;
a3b58b4a 1475
d62a17ae 1476 return 0;
cb40b272 1477}
d7259eac 1478
d62a17ae 1479int pim_upstream_is_sg_rpt(struct pim_upstream *up)
80d9c3a0 1480{
d62a17ae 1481 struct listnode *chnode;
1482 struct pim_ifchannel *ch;
f21597f0 1483
d62a17ae 1484 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1485 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1486 return 1;
1487 }
e43b8697 1488
d62a17ae 1489 return 0;
80d9c3a0 1490}
3a66b17b
DS
1491/*
1492 * After receiving a packet set SPTbit:
1493 * void
1494 * Update_SPTbit(S,G,iif) {
1495 * if ( iif == RPF_interface(S)
2951a7a4
QY
1496 * AND JoinDesired(S,G) == true
1497 * AND ( DirectlyConnected(S) == true
3a66b17b
DS
1498 * OR RPF_interface(S) != RPF_interface(RP(G))
1499 * OR inherited_olist(S,G,rpt) == NULL
1500 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1501 * ( RPF'(S,G) != NULL ) )
1502 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
2951a7a4 1503 * Set SPTbit(S,G) to true
3a66b17b
DS
1504 * }
1505 * }
1506 */
d62a17ae 1507void pim_upstream_set_sptbit(struct pim_upstream *up,
1508 struct interface *incoming)
3a66b17b 1509{
d62a17ae 1510 struct pim_upstream *starup = up->parent;
1511
1512 // iif == RPF_interfvace(S)
1513 if (up->rpf.source_nexthop.interface != incoming) {
23fc858a 1514 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1515 zlog_debug(
1516 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1517 __PRETTY_FUNCTION__, incoming->name,
1518 up->rpf.source_nexthop.interface->name);
1519 return;
1520 }
1521
2951a7a4 1522 // AND JoinDesired(S,G) == true
6f0f014f 1523 if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) {
23fc858a 1524 if (PIM_DEBUG_PIM_TRACE)
6f0f014f
DS
1525 zlog_debug("%s: %s Join is not Desired",
1526 __PRETTY_FUNCTION__, up->sg_str);
1527 return;
1528 }
d62a17ae 1529
2951a7a4 1530 // DirectlyConnected(S) == true
d62a17ae 1531 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1532 up->sg.src)) {
23fc858a 1533 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1534 zlog_debug("%s: %s is directly connected to the source",
1535 __PRETTY_FUNCTION__, up->sg_str);
1536 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1537 return;
1538 }
1539
1540 // OR RPF_interface(S) != RPF_interface(RP(G))
1541 if (!starup
1542 || up->rpf.source_nexthop
1543 .interface != starup->rpf.source_nexthop.interface) {
2de05c60
DS
1544 struct pim_upstream *starup = up->parent;
1545
23fc858a 1546 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1547 zlog_debug(
1548 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1549 __PRETTY_FUNCTION__, up->sg_str);
1550 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
2de05c60
DS
1551
1552 pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
d62a17ae 1553 return;
1554 }
1555
1556 // OR inherited_olist(S,G,rpt) == NULL
1557 if (pim_upstream_is_sg_rpt(up)
1558 && pim_upstream_empty_inherited_olist(up)) {
23fc858a 1559 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1560 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1561 __PRETTY_FUNCTION__, up->sg_str);
1562 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1563 return;
1564 }
1565
1566 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1567 // ( RPF'(S,G) != NULL ) )
1568 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
23fc858a 1569 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1570 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1571 __PRETTY_FUNCTION__, up->sg_str);
1572 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1573 return;
1574 }
1575
1576 return;
3a66b17b 1577}
80d9c3a0 1578
d62a17ae 1579const char *pim_upstream_state2str(enum pim_upstream_state join_state)
d7259eac 1580{
d62a17ae 1581 switch (join_state) {
1582 case PIM_UPSTREAM_NOTJOINED:
1583 return "NotJoined";
1584 break;
1585 case PIM_UPSTREAM_JOINED:
1586 return "Joined";
1587 break;
1588 }
1589 return "Unknown";
d7259eac 1590}
627ed2a3 1591
c35b7e6b
QY
1592const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
1593 size_t state_str_len)
e0e127b0 1594{
d62a17ae 1595 switch (reg_state) {
1596 case PIM_REG_NOINFO:
c35b7e6b 1597 strlcpy(state_str, "RegNoInfo", state_str_len);
d62a17ae 1598 break;
1599 case PIM_REG_JOIN:
c35b7e6b 1600 strlcpy(state_str, "RegJoined", state_str_len);
d62a17ae 1601 break;
1602 case PIM_REG_JOIN_PENDING:
c35b7e6b 1603 strlcpy(state_str, "RegJoinPend", state_str_len);
d62a17ae 1604 break;
1605 case PIM_REG_PRUNE:
c35b7e6b 1606 strlcpy(state_str, "RegPrune", state_str_len);
d62a17ae 1607 break;
1608 default:
c35b7e6b 1609 strlcpy(state_str, "RegUnknown", state_str_len);
d62a17ae 1610 }
1611 return state_str;
e0e127b0 1612}
1613
d62a17ae 1614static int pim_upstream_register_stop_timer(struct thread *t)
627ed2a3 1615{
d62a17ae 1616 struct pim_interface *pim_ifp;
8e5f97e3 1617 struct pim_instance *pim;
d62a17ae 1618 struct pim_upstream *up;
d62a17ae 1619 up = THREAD_ARG(t);
8e5f97e3 1620 pim = up->channel_oil->pim;
d62a17ae 1621
23fc858a 1622 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1623 char state_str[PIM_REG_STATE_STR_LEN];
8dbdb215
DS
1624 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1625 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
c35b7e6b 1626 pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
d62a17ae 1627 }
1628
1629 switch (up->reg_state) {
1630 case PIM_REG_JOIN_PENDING:
1631 up->reg_state = PIM_REG_JOIN;
8e5f97e3 1632 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
1633 PIM_OIF_FLAG_PROTO_PIM,
1634 __func__);
2951a7a4 1635 pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
d62a17ae 1636 break;
1637 case PIM_REG_JOIN:
1638 break;
1639 case PIM_REG_PRUNE:
957d93ea 1640 if (!up->rpf.source_nexthop.interface) {
23fc858a 1641 if (PIM_DEBUG_PIM_TRACE)
957d93ea
SP
1642 zlog_debug("%s: up %s RPF is not present",
1643 __PRETTY_FUNCTION__, up->sg_str);
1644 return 0;
1645 }
1646
d62a17ae 1647 pim_ifp = up->rpf.source_nexthop.interface->info;
1648 if (!pim_ifp) {
23fc858a 1649 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1650 zlog_debug(
1651 "%s: Interface: %s is not configured for pim",
1652 __PRETTY_FUNCTION__,
1653 up->rpf.source_nexthop.interface->name);
1654 return 0;
1655 }
1656 up->reg_state = PIM_REG_JOIN_PENDING;
1657 pim_upstream_start_register_stop_timer(up, 1);
1658
1659 if (((up->channel_oil->cc.lastused / 100)
2f5b0028 1660 > pim->keep_alive_time)
d9c9a9ee 1661 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
23fc858a 1662 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1663 zlog_debug(
1664 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1665 __PRETTY_FUNCTION__);
1666 return 0;
1667 }
aea1f845 1668 pim_null_register_send(up);
d62a17ae 1669 break;
1670 default:
1671 break;
70e7fda8 1672 }
d62a17ae 1673
1674 return 0;
627ed2a3
DS
1675}
1676
d62a17ae 1677void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1678 int null_register)
627ed2a3 1679{
d62a17ae 1680 uint32_t time;
1681
1682 THREAD_TIMER_OFF(up->t_rs_timer);
1683
1684 if (!null_register) {
1685 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1686 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1687 time = lower + (random() % (upper - lower + 1))
1688 - PIM_REGISTER_PROBE_PERIOD;
1689 } else
1690 time = PIM_REGISTER_PROBE_PERIOD;
1691
23fc858a 1692 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1693 zlog_debug(
1694 "%s: (S,G)=%s Starting upstream register stop timer %d",
1695 __PRETTY_FUNCTION__, up->sg_str, time);
1696 }
36417fcc
DS
1697 thread_add_timer(router->master, pim_upstream_register_stop_timer, up,
1698 time, &up->t_rs_timer);
627ed2a3 1699}
4fdc8f36 1700
9b29ea95
DS
1701int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1702 struct pim_upstream *up)
4fdc8f36 1703{
d62a17ae 1704 struct interface *ifp;
d62a17ae 1705 struct pim_ifchannel *ch, *starch;
d62a17ae 1706 struct pim_upstream *starup = up->parent;
1707 int output_intf = 0;
1708
46dd6edb 1709 if (!up->rpf.source_nexthop.interface)
23fc858a 1710 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1711 zlog_debug("%s: up %s RPF is not present",
1712 __PRETTY_FUNCTION__, up->sg_str);
d62a17ae 1713
451fda4f 1714 FOR_ALL_INTERFACES (pim->vrf, ifp) {
d62a17ae 1715 if (!ifp->info)
1716 continue;
1717
1718 ch = pim_ifchannel_find(ifp, &up->sg);
1719
1720 if (starup)
1721 starch = pim_ifchannel_find(ifp, &starup->sg);
1722 else
1723 starch = NULL;
1724
1725 if (!ch && !starch)
1726 continue;
1727
1728 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1729 starch)) {
1730 int flag = PIM_OIF_FLAG_PROTO_PIM;
1731
1732 if (!ch)
1733 flag = PIM_OIF_FLAG_PROTO_STAR;
1734
1b249e70
AK
1735 pim_channel_add_oif(up->channel_oil, ifp, flag,
1736 __func__);
d62a17ae 1737 output_intf++;
1738 }
1739 }
1740
1741 return output_intf;
b5183fd1
DS
1742}
1743
1744/*
1745 * For a given upstream, determine the inherited_olist
1746 * and apply it.
1747 *
1748 * inherited_olist(S,G,rpt) =
1749 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1750 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1751 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1752 *
1753 * inherited_olist(S,G) =
1754 * inherited_olist(S,G,rpt) (+)
1755 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1756 *
1757 * return 1 if there are any output interfaces
1758 * return 0 if there are not any output interfaces
1759 */
9b29ea95
DS
1760int pim_upstream_inherited_olist(struct pim_instance *pim,
1761 struct pim_upstream *up)
b5183fd1 1762{
9b29ea95 1763 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1764
1765 /*
1766 * If we have output_intf switch state to Join and work like normal
1767 * If we don't have an output_intf that means we are probably a
1768 * switch on a stick so turn on forwarding to just accept the
1769 * incoming packets so we don't bother the other stuff!
1770 */
a53a9b3e
AK
1771 pim_upstream_update_join_desired(pim, up);
1772
1773 if (!output_intf)
d62a17ae 1774 forward_on(up);
1775
1776 return output_intf;
4fdc8f36 1777}
d3dd1804 1778
d62a17ae 1779int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
80d9c3a0 1780{
d62a17ae 1781 return pim_channel_oil_empty(up->channel_oil);
80d9c3a0
DS
1782}
1783
d3dd1804
DS
1784/*
1785 * When we have a new neighbor,
1786 * find upstreams that don't have their rpf_addr
1787 * set and see if the new neighbor allows
1788 * the join to be sent
1789 */
9b29ea95 1790void pim_upstream_find_new_rpf(struct pim_instance *pim)
d3dd1804 1791{
d62a17ae 1792 struct listnode *up_node;
1793 struct listnode *up_nextnode;
1794 struct pim_upstream *up;
7ef66af9
AK
1795 struct pim_rpf old;
1796 enum pim_rpf_result rpf_result;
d62a17ae 1797
1798 /*
1799 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1800 */
9b29ea95 1801 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
957d93ea 1802 if (up->upstream_addr.s_addr == INADDR_ANY) {
23fc858a 1803 if (PIM_DEBUG_PIM_TRACE)
957d93ea
SP
1804 zlog_debug(
1805 "%s: RP not configured for Upstream %s",
1806 __PRETTY_FUNCTION__, up->sg_str);
1807 continue;
1808 }
1809
d62a17ae 1810 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
23fc858a 1811 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1812 zlog_debug(
957d93ea
SP
1813 "%s: Upstream %s without a path to send join, checking",
1814 __PRETTY_FUNCTION__, up->sg_str);
075a475e
AK
1815 old.source_nexthop.interface =
1816 up->rpf.source_nexthop.interface;
7ef66af9 1817 rpf_result = pim_rpf_update(pim, up, &old, __func__);
b36576e4
AK
1818 if (rpf_result == PIM_RPF_CHANGED ||
1819 (rpf_result == PIM_RPF_FAILURE &&
1820 old.source_nexthop.interface))
7ef66af9
AK
1821 pim_zebra_upstream_rpf_changed(pim, up, &old);
1822 /* update kernel multicast forwarding cache (MFC) */
075a475e
AK
1823 pim_upstream_mroute_iif_update(up->channel_oil,
1824 __func__);
d62a17ae 1825 }
d3dd1804 1826 }
7ef66af9 1827 pim_zebra_update_all_interfaces(pim);
d3dd1804 1828}
0f588989 1829
d8b87afe 1830unsigned int pim_upstream_hash_key(const void *arg)
0f588989 1831{
d8b87afe 1832 const struct pim_upstream *up = arg;
0f588989 1833
d62a17ae 1834 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
0f588989
DS
1835}
1836
9b29ea95 1837void pim_upstream_terminate(struct pim_instance *pim)
0f588989 1838{
172e45dc
DS
1839 struct pim_upstream *up;
1840
1841 if (pim->upstream_list) {
1d483838
DS
1842 while (pim->upstream_list->count) {
1843 up = listnode_head(pim->upstream_list);
172e45dc 1844 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1d483838 1845 }
172e45dc 1846
6a154c88 1847 list_delete(&pim->upstream_list);
172e45dc 1848 }
0f588989 1849
9b29ea95
DS
1850 if (pim->upstream_hash)
1851 hash_free(pim->upstream_hash);
1852 pim->upstream_hash = NULL;
0c68972d
DS
1853
1854 if (pim->upstream_sg_wheel)
1855 wheel_delete(pim->upstream_sg_wheel);
1856 pim->upstream_sg_wheel = NULL;
0f588989
DS
1857}
1858
74df8d6d 1859bool pim_upstream_equal(const void *arg1, const void *arg2)
0f588989 1860{
d62a17ae 1861 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1862 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
0f588989 1863
d62a17ae 1864 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1865 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
74df8d6d 1866 return true;
0f588989 1867
74df8d6d 1868 return false;
0f588989
DS
1869}
1870
1bf16443 1871/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1872 * the cases where kat has to be restarted on rxing traffic -
1873 *
2951a7a4 1874 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1bf16443 1875 * set KeepaliveTimer(S,G) to Keepalive_Period
1876 * # Note: a register state transition or UpstreamJPState(S,G)
1877 * # transition may happen as a result of restarting
1878 * # KeepaliveTimer, and must be dealt with here.
1879 * }
1880 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1881 * inherited_olist(S,G) != NULL ) {
1882 * set KeepaliveTimer(S,G) to Keepalive_Period
1883 * }
1884 */
1885static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1886{
cfa8f7eb
AK
1887 struct channel_oil *c_oil = up->channel_oil;
1888 struct interface *ifp = up->rpf.source_nexthop.interface;
1889 struct pim_interface *pim_ifp;
1890
1891 /* "iif == RPF_interface(S)" check is not easy to do as the info
1892 * we get from the kernel/ASIC is really a "lookup/key hit".
1893 * So we will do an approximate check here to avoid starting KAT
1894 * because of (S,G,rpt) forwarding on a non-LHR.
1895 */
1896 if (!ifp)
1897 return false;
1898
1899 pim_ifp = ifp->info;
1900 if (pim_ifp->mroute_vif_index != c_oil->oil.mfcc_parent)
1901 return false;
8e5f97e3 1902
a1be0939 1903 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
d62a17ae 1904 up->sg.src)) {
1905 return true;
1906 }
1907
1908 if ((up->join_state == PIM_UPSTREAM_JOINED)
cfa8f7eb
AK
1909 && !pim_upstream_empty_inherited_olist(up)) {
1910 return true;
d62a17ae 1911 }
1912
1913 return false;
1bf16443 1914}
1915
9c5e4d62
DS
1916/*
1917 * Code to check and see if we've received packets on a S,G mroute
1918 * and if so to set the SPT bit appropriately
1919 */
d62a17ae 1920static void pim_upstream_sg_running(void *arg)
9c5e4d62 1921{
d62a17ae 1922 struct pim_upstream *up = (struct pim_upstream *)arg;
8e5f97e3 1923 struct pim_instance *pim = up->channel_oil->pim;
d62a17ae 1924
1925 // No packet can have arrived here if this is the case
8e5f97e3 1926 if (!up->channel_oil->installed) {
23fc858a 1927 if (PIM_DEBUG_PIM_TRACE)
41714081 1928 zlog_debug("%s: %s%s is not installed in mroute",
996c9314
LB
1929 __PRETTY_FUNCTION__, up->sg_str,
1930 pim->vrf->name);
d62a17ae 1931 return;
1932 }
1933
1934 /*
1935 * This is a bit of a hack
1936 * We've noted that we should rescan but
1937 * we've missed the window for doing so in
1938 * pim_zebra.c for some reason. I am
1939 * only doing this at this point in time
1940 * to get us up and working for the moment
1941 */
1942 if (up->channel_oil->oil_inherited_rescan) {
23fc858a 1943 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1944 zlog_debug(
8dbdb215 1945 "%s: Handling unscanned inherited_olist for %s[%s]",
996c9314
LB
1946 __PRETTY_FUNCTION__, up->sg_str,
1947 pim->vrf->name);
8e5f97e3 1948 pim_upstream_inherited_olist_decide(pim, up);
d62a17ae 1949 up->channel_oil->oil_inherited_rescan = 0;
1950 }
1951 pim_mroute_update_counters(up->channel_oil);
1952
1953 // Have we seen packets?
1954 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1955 && (up->channel_oil->cc.lastused / 100 > 30)) {
23fc858a 1956 if (PIM_DEBUG_PIM_TRACE) {
d62a17ae 1957 zlog_debug(
8dbdb215
DS
1958 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1959 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
d62a17ae 1960 up->channel_oil->cc.oldpktcnt,
1961 up->channel_oil->cc.pktcnt,
1962 up->channel_oil->cc.lastused / 100);
1963 }
1964 return;
e43b8697 1965 }
d62a17ae 1966
1967 if (pim_upstream_kat_start_ok(up)) {
1968 /* Add a source reference to the stream if
1969 * one doesn't already exist */
1970 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
23fc858a 1971 if (PIM_DEBUG_PIM_TRACE)
d62a17ae 1972 zlog_debug(
8dbdb215
DS
1973 "source reference created on kat restart %s[%s]",
1974 up->sg_str, pim->vrf->name);
d62a17ae 1975
1976 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1977 __PRETTY_FUNCTION__);
1978 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1979 pim_upstream_fhr_kat_start(up);
1980 }
19b807ca 1981 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1982 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
19b807ca 1983 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
d62a17ae 1984
957d93ea
SP
1985 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
1986 (up->rpf.source_nexthop.interface)) {
d62a17ae 1987 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
850a9f99 1988 }
d62a17ae 1989 return;
9c5e4d62
DS
1990}
1991
9b29ea95 1992void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
a7b2b1e2 1993{
d62a17ae 1994 struct pim_upstream *up;
1995 struct listnode *node;
a7b2b1e2 1996
9b29ea95 1997 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 1998 if (up->sg.src.s_addr != INADDR_ANY)
1999 continue;
a7b2b1e2 2000
d62a17ae 2001 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
2002 continue;
a7b2b1e2 2003
9b29ea95 2004 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70 2005 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 2006 }
a7b2b1e2
DS
2007}
2008
9b29ea95
DS
2009void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
2010 struct prefix_list *pl)
df94f9a9 2011{
d62a17ae 2012 const char *pname = prefix_list_name(pl);
df94f9a9 2013
9b29ea95
DS
2014 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
2015 pim_upstream_remove_lhr_star_pimreg(pim, pname);
d62a17ae 2016 }
df94f9a9
DS
2017}
2018
2019/*
2020 * nlist -> The new prefix list
2021 *
2022 * Per Group Application of pimreg to the OIL
2023 * If the prefix list tells us DENY then
2024 * we need to Switchover to SPT immediate
2025 * so add the pimreg.
2026 * If the prefix list tells us to ACCEPT than
2027 * we need to Never do the SPT so remove
2028 * the interface
2029 *
2030 */
9b29ea95
DS
2031void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
2032 const char *nlist)
a7b2b1e2 2033{
d62a17ae 2034 struct pim_upstream *up;
2035 struct listnode *node;
2036 struct prefix_list *np;
2037 struct prefix g;
2038 enum prefix_list_type apply_new;
2039
2040 np = prefix_list_lookup(AFI_IP, nlist);
2041
2042 g.family = AF_INET;
2043 g.prefixlen = IPV4_MAX_PREFIXLEN;
2044
9b29ea95 2045 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
d62a17ae 2046 if (up->sg.src.s_addr != INADDR_ANY)
2047 continue;
2048
2049 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
2050 continue;
2051
2052 if (!nlist) {
9b29ea95 2053 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 2054 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 2055 continue;
2056 }
2057 g.u.prefix4 = up->sg.grp;
2058 apply_new = prefix_list_apply(np, &g);
2059 if (apply_new == PREFIX_DENY)
9b29ea95 2060 pim_channel_add_oif(up->channel_oil, pim->regiface,
1b249e70
AK
2061 PIM_OIF_FLAG_PROTO_IGMP,
2062 __func__);
d62a17ae 2063 else
9b29ea95 2064 pim_channel_del_oif(up->channel_oil, pim->regiface,
1b249e70 2065 PIM_OIF_FLAG_PROTO_IGMP, __func__);
d62a17ae 2066 }
a7b2b1e2
DS
2067}
2068
9b29ea95 2069void pim_upstream_init(struct pim_instance *pim)
0f588989 2070{
c2cfa843 2071 char name[64];
9fb302f4 2072
c2cfa843
DS
2073 snprintf(name, 64, "PIM %s Timer Wheel",
2074 pim->vrf->name);
9b29ea95 2075 pim->upstream_sg_wheel =
36417fcc 2076 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
c2cfa843 2077 pim_upstream_sg_running, name);
9fb302f4 2078
c2cfa843
DS
2079 snprintf(name, 64, "PIM %s Upstream Hash",
2080 pim->vrf->name);
9b29ea95 2081 pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
c2cfa843 2082 pim_upstream_equal, name);
d62a17ae 2083
9b29ea95 2084 pim->upstream_list = list_new();
9b29ea95 2085 pim->upstream_list->cmp = pim_upstream_compare;
0f588989 2086}