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