]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
Merge pull request #10547 from donaldsharp/10458
[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 struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
182 struct pim_upstream *up, const char *name)
183 {
184 struct listnode *node, *nnode;
185 struct pim_ifchannel *ch;
186 bool notify_msdp = false;
187 struct prefix nht_p;
188
189 if (PIM_DEBUG_PIM_TRACE)
190 zlog_debug(
191 "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
192 __func__, name, up->sg_str, pim->vrf->name,
193 up->ref_count, up->flags,
194 up->channel_oil->oil_ref_count);
195
196 assert(up->ref_count > 0);
197
198 --up->ref_count;
199
200 if (up->ref_count >= 1)
201 return up;
202
203 if (PIM_DEBUG_TRACE)
204 zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
205 pim->vrf->name, up->sg_str, up->flags);
206
207 if (pim_up_mlag_is_local(up))
208 pim_mlag_up_local_del(pim, up);
209
210 THREAD_OFF(up->t_ka_timer);
211 THREAD_OFF(up->t_rs_timer);
212 THREAD_OFF(up->t_msdp_reg_timer);
213
214 if (up->join_state == PIM_UPSTREAM_JOINED) {
215 pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
216
217 if (pim_addr_is_any(up->sg.src)) {
218 /* if a (*, G) entry in the joined state is being
219 * deleted we
220 * need to notify MSDP */
221 notify_msdp = true;
222 }
223 }
224
225 join_timer_stop(up);
226 pim_jp_agg_upstream_verification(up, false);
227 up->rpf.source_nexthop.interface = NULL;
228
229 if (!pim_addr_is_any(up->sg.src)) {
230 if (pim->upstream_sg_wheel)
231 wheel_remove_item(pim->upstream_sg_wheel, up);
232 notify_msdp = true;
233 }
234
235 pim_mroute_del(up->channel_oil, __func__);
236 upstream_channel_oil_detach(up);
237
238 for (ALL_LIST_ELEMENTS(up->ifchannels, node, nnode, ch))
239 pim_ifchannel_delete(ch);
240 list_delete(&up->ifchannels);
241
242 pim_upstream_remove_children(pim, up);
243 if (up->sources)
244 list_delete(&up->sources);
245
246 if (up->parent && up->parent->sources)
247 listnode_delete(up->parent->sources, up);
248 up->parent = NULL;
249
250 rb_pim_upstream_del(&pim->upstream_head, up);
251
252 if (notify_msdp) {
253 pim_msdp_up_del(pim, &up->sg);
254 }
255
256 /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
257 * and assign up->upstream_addr as INADDR_ANY.
258 * So before de-registering the upstream address, check if is not equal
259 * to INADDR_ANY. This is done in order to avoid de-registering for
260 * 255.255.255.255 which is maintained for some reason..
261 */
262 if (!pim_addr_is_any(up->upstream_addr)) {
263 /* Deregister addr with Zebra NHT */
264 pim_addr_to_prefix(&nht_p, up->upstream_addr);
265 if (PIM_DEBUG_PIM_TRACE)
266 zlog_debug(
267 "%s: Deregister upstream %s addr %pFX with Zebra NHT",
268 __func__, up->sg_str, &nht_p);
269 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
270 }
271
272 XFREE(MTYPE_PIM_UPSTREAM, up);
273
274 return NULL;
275 }
276
277 void pim_upstream_send_join(struct pim_upstream *up)
278 {
279 if (!up->rpf.source_nexthop.interface) {
280 if (PIM_DEBUG_PIM_TRACE)
281 zlog_debug("%s: up %s RPF is not present", __func__,
282 up->sg_str);
283 return;
284 }
285
286 if (PIM_DEBUG_PIM_TRACE) {
287 char rpf_str[PREFIX_STRLEN];
288 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
289 sizeof(rpf_str));
290 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s", __func__,
291 up->sg_str, rpf_str,
292 pim_upstream_state2str(up->join_state),
293 up->rpf.source_nexthop.interface->name);
294 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
295 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
296 __func__, up->sg_str, rpf_str);
297 /* warning only */
298 }
299 }
300
301 /* send Join(S,G) to the current upstream neighbor */
302 pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
303 }
304
305 static int on_join_timer(struct thread *t)
306 {
307 struct pim_upstream *up;
308
309 up = THREAD_ARG(t);
310
311 if (!up->rpf.source_nexthop.interface) {
312 if (PIM_DEBUG_PIM_TRACE)
313 zlog_debug("%s: up %s RPF is not present", __func__,
314 up->sg_str);
315 return 0;
316 }
317
318 /*
319 * In the case of a HFR we will not ahve anyone to send this to.
320 */
321 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
322 return 0;
323
324 /*
325 * Don't send the join if the outgoing interface is a loopback
326 * But since this might change leave the join timer running
327 */
328 if (up->rpf.source_nexthop
329 .interface && !if_is_loopback(up->rpf.source_nexthop.interface))
330 pim_upstream_send_join(up);
331
332 join_timer_start(up);
333
334 return 0;
335 }
336
337 static void join_timer_stop(struct pim_upstream *up)
338 {
339 struct pim_neighbor *nbr = NULL;
340
341 THREAD_OFF(up->t_join_timer);
342
343 if (up->rpf.source_nexthop.interface)
344 nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
345 &up->rpf.rpf_addr);
346
347 if (nbr)
348 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
349
350 pim_jp_agg_upstream_verification(up, false);
351 }
352
353 void join_timer_start(struct pim_upstream *up)
354 {
355 struct pim_neighbor *nbr = NULL;
356
357 if (up->rpf.source_nexthop.interface) {
358 nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
359 &up->rpf.rpf_addr);
360
361 if (PIM_DEBUG_PIM_EVENTS) {
362 zlog_debug(
363 "%s: starting %d sec timer for upstream (S,G)=%s",
364 __func__, router->t_periodic, up->sg_str);
365 }
366 }
367
368 if (nbr)
369 pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1, nbr);
370 else {
371 THREAD_OFF(up->t_join_timer);
372 thread_add_timer(router->master, on_join_timer, up,
373 router->t_periodic, &up->t_join_timer);
374 }
375 pim_jp_agg_upstream_verification(up, true);
376 }
377
378 /*
379 * This is only called when we are switching the upstream
380 * J/P from one neighbor to another
381 *
382 * As such we need to remove from the old list and
383 * add to the new list.
384 */
385 void pim_upstream_join_timer_restart(struct pim_upstream *up,
386 struct pim_rpf *old)
387 {
388 // THREAD_OFF(up->t_join_timer);
389 join_timer_start(up);
390 }
391
392 static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
393 int interval_msec)
394 {
395 if (PIM_DEBUG_PIM_EVENTS) {
396 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
397 __func__, interval_msec, up->sg_str);
398 }
399
400 THREAD_OFF(up->t_join_timer);
401 thread_add_timer_msec(router->master, on_join_timer, up, interval_msec,
402 &up->t_join_timer);
403 }
404
405 void pim_update_suppress_timers(uint32_t suppress_time)
406 {
407 struct pim_instance *pim;
408 struct vrf *vrf;
409 unsigned int old_rp_ka_time;
410
411 /* stash the old one so we know which values were manually configured */
412 old_rp_ka_time = (3 * router->register_suppress_time
413 + router->register_probe_time);
414 router->register_suppress_time = suppress_time;
415
416 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
417 pim = vrf->info;
418 if (!pim)
419 continue;
420
421 /* Only adjust if not manually configured */
422 if (pim->rp_keep_alive_time == old_rp_ka_time)
423 pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
424 }
425 }
426
427 void pim_upstream_join_suppress(struct pim_upstream *up,
428 struct in_addr rpf_addr, int holdtime)
429 {
430 long t_joinsuppress_msec;
431 long join_timer_remain_msec = 0;
432 struct pim_neighbor *nbr = NULL;
433
434 if (!up->rpf.source_nexthop.interface) {
435 if (PIM_DEBUG_PIM_TRACE)
436 zlog_debug("%s: up %s RPF is not present", __func__,
437 up->sg_str);
438 return;
439 }
440
441 t_joinsuppress_msec =
442 MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
443 1000 * holdtime);
444
445 if (up->t_join_timer)
446 join_timer_remain_msec =
447 pim_time_timer_remain_msec(up->t_join_timer);
448 else {
449 /* Remove it from jp agg from the nbr for suppression */
450 nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
451 &up->rpf.rpf_addr);
452 if (nbr) {
453 join_timer_remain_msec =
454 pim_time_timer_remain_msec(nbr->jp_timer);
455 }
456 }
457
458 if (PIM_DEBUG_PIM_TRACE) {
459 char rpf_str[INET_ADDRSTRLEN];
460 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
461 zlog_debug(
462 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
463 __FILE__, __func__, up->sg_str, rpf_str,
464 join_timer_remain_msec, t_joinsuppress_msec);
465 }
466
467 if (join_timer_remain_msec < t_joinsuppress_msec) {
468 if (PIM_DEBUG_PIM_TRACE) {
469 zlog_debug(
470 "%s %s: suppressing Join(S,G)=%s for %ld msec",
471 __FILE__, __func__, up->sg_str,
472 t_joinsuppress_msec);
473 }
474
475 if (nbr)
476 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
477
478 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
479 }
480 }
481
482 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
483 struct pim_upstream *up)
484 {
485 long join_timer_remain_msec;
486 int t_override_msec;
487
488 if (!up->rpf.source_nexthop.interface) {
489 if (PIM_DEBUG_PIM_TRACE)
490 zlog_debug("%s: up %s RPF is not present", __func__,
491 up->sg_str);
492 return;
493 }
494
495 t_override_msec =
496 pim_if_t_override_msec(up->rpf.source_nexthop.interface);
497
498 if (up->t_join_timer) {
499 join_timer_remain_msec =
500 pim_time_timer_remain_msec(up->t_join_timer);
501 } else {
502 /* upstream join tracked with neighbor jp timer */
503 struct pim_neighbor *nbr;
504
505 nbr = pim_neighbor_find_prefix(up->rpf.source_nexthop.interface,
506 &up->rpf.rpf_addr);
507 if (nbr)
508 join_timer_remain_msec =
509 pim_time_timer_remain_msec(nbr->jp_timer);
510 else
511 /* Manipulate such that override takes place */
512 join_timer_remain_msec = t_override_msec + 1;
513 }
514
515 if (PIM_DEBUG_PIM_TRACE) {
516 char rpf_str[INET_ADDRSTRLEN];
517 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str,
518 sizeof(rpf_str));
519 zlog_debug(
520 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
521 debug_label, up->sg_str, rpf_str,
522 join_timer_remain_msec, t_override_msec);
523 }
524
525 if (join_timer_remain_msec > t_override_msec) {
526 if (PIM_DEBUG_PIM_TRACE) {
527 zlog_debug(
528 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
529 debug_label, up->sg_str, t_override_msec);
530 }
531
532 pim_upstream_join_timer_restart_msec(up, t_override_msec);
533 }
534 }
535
536 static void forward_on(struct pim_upstream *up)
537 {
538 struct listnode *chnode;
539 struct listnode *chnextnode;
540 struct pim_ifchannel *ch = NULL;
541
542 /* scan (S,G) state */
543 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
544 if (pim_macro_chisin_oiflist(ch))
545 pim_forward_start(ch);
546
547 } /* scan iface channel list */
548 }
549
550 static void forward_off(struct pim_upstream *up)
551 {
552 struct listnode *chnode;
553 struct listnode *chnextnode;
554 struct pim_ifchannel *ch;
555
556 /* scan per-interface (S,G) state */
557 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
558
559 pim_forward_stop(ch);
560
561 } /* scan iface channel list */
562 }
563
564 int pim_upstream_could_register(struct pim_upstream *up)
565 {
566 struct pim_interface *pim_ifp = NULL;
567
568 /* FORCE_PIMREG is a generic flag to let an app like VxLAN-AA register
569 * a source on an upstream entry even if the source is not directly
570 * connected on the IIF.
571 */
572 if (PIM_UPSTREAM_FLAG_TEST_FORCE_PIMREG(up->flags))
573 return 1;
574
575 if (up->rpf.source_nexthop.interface)
576 pim_ifp = up->rpf.source_nexthop.interface->info;
577 else {
578 if (PIM_DEBUG_PIM_TRACE)
579 zlog_debug("%s: up %s RPF is not present", __func__,
580 up->sg_str);
581 }
582
583 if (pim_ifp && PIM_I_am_DR(pim_ifp)
584 && pim_if_connected_to_source(up->rpf.source_nexthop.interface,
585 up->sg.src))
586 return 1;
587
588 return 0;
589 }
590
591 /* Source registration is suppressed for SSM groups. When the SSM range changes
592 * we re-revaluate register setup for existing upstream entries */
593 void pim_upstream_register_reevaluate(struct pim_instance *pim)
594 {
595 struct pim_upstream *up;
596
597 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
598 /* If FHR is set CouldRegister is True. Also check if the flow
599 * is actually active; if it is not kat setup will trigger
600 * source
601 * registration whenever the flow becomes active. */
602 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
603 !pim_upstream_is_kat_running(up))
604 continue;
605
606 if (pim_is_grp_ssm(pim, up->sg.grp)) {
607 /* clear the register state for SSM groups */
608 if (up->reg_state != PIM_REG_NOINFO) {
609 if (PIM_DEBUG_PIM_EVENTS)
610 zlog_debug(
611 "Clear register for %s as G is now SSM",
612 up->sg_str);
613 /* remove regiface from the OIL if it is there*/
614 pim_channel_del_oif(up->channel_oil,
615 pim->regiface,
616 PIM_OIF_FLAG_PROTO_PIM,
617 __func__);
618 up->reg_state = PIM_REG_NOINFO;
619 }
620 } else {
621 /* register ASM sources with the RP */
622 if (up->reg_state == PIM_REG_NOINFO) {
623 if (PIM_DEBUG_PIM_EVENTS)
624 zlog_debug(
625 "Register %s as G is now ASM",
626 up->sg_str);
627 pim_channel_add_oif(up->channel_oil,
628 pim->regiface,
629 PIM_OIF_FLAG_PROTO_PIM,
630 __func__);
631 up->reg_state = PIM_REG_JOIN;
632 }
633 }
634 }
635 }
636
637 /* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should
638 * forward a S -
639 * 1. along the SPT if SPTbit is set
640 * 2. and along the RPT if SPTbit is not set
641 * If forwarding is hw accelerated i.e. control and dataplane components
642 * are separate you may not be able to reliably set SPT bit on intermediate
643 * routers while still fowarding on the (S,G,rpt).
644 *
645 * This macro is a slight deviation on the RFC and uses "traffic-agnostic"
646 * criteria to decide between using the RPT vs. SPT for forwarding.
647 */
648 void pim_upstream_update_use_rpt(struct pim_upstream *up,
649 bool update_mroute)
650 {
651 bool old_use_rpt;
652 bool new_use_rpt;
653
654 if (pim_addr_is_any(up->sg.src))
655 return;
656
657 old_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
658
659 /* We will use the SPT (IIF=RPF_interface(S) if -
660 * 1. We have decided to join the SPT
661 * 2. We are FHR
662 * 3. Source is directly connected
663 * 4. We are RP (parent's IIF is lo or vrf-device)
664 * In all other cases the source will stay along the RPT and
665 * IIF=RPF_interface(RP).
666 */
667 if (up->join_state == PIM_UPSTREAM_JOINED ||
668 PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) ||
669 pim_if_connected_to_source(
670 up->rpf.source_nexthop.interface,
671 up->sg.src) ||
672 /* XXX - need to switch this to a more efficient
673 * lookup API
674 */
675 I_am_RP(up->pim, up->sg.grp))
676 /* use SPT */
677 PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags);
678 else
679 /* use RPT */
680 PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags);
681
682 new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
683 if (old_use_rpt != new_use_rpt) {
684 if (PIM_DEBUG_PIM_EVENTS)
685 zlog_debug("%s switched from %s to %s",
686 up->sg_str,
687 old_use_rpt?"RPT":"SPT",
688 new_use_rpt?"RPT":"SPT");
689 if (update_mroute)
690 pim_upstream_mroute_add(up->channel_oil, __func__);
691 }
692 }
693
694 /* some events like RP change require re-evaluation of SGrpt across
695 * all groups
696 */
697 void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
698 {
699 struct pim_upstream *up;
700
701 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
702 if (pim_addr_is_any(up->sg.src))
703 continue;
704
705 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
706 }
707 }
708
709 void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
710 enum pim_upstream_state new_state)
711 {
712 enum pim_upstream_state old_state = up->join_state;
713
714 if (pim_addr_is_any(up->upstream_addr)) {
715 if (PIM_DEBUG_PIM_EVENTS)
716 zlog_debug("%s: RPF not configured for %s", __func__,
717 up->sg_str);
718 return;
719 }
720
721 if (!up->rpf.source_nexthop.interface) {
722 if (PIM_DEBUG_PIM_EVENTS)
723 zlog_debug("%s: RP not reachable for %s", __func__,
724 up->sg_str);
725 return;
726 }
727
728 if (PIM_DEBUG_PIM_EVENTS) {
729 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
730 __func__, up->sg_str,
731 pim_upstream_state2str(up->join_state),
732 pim_upstream_state2str(new_state));
733 }
734
735 up->join_state = new_state;
736 if (old_state != new_state)
737 up->state_transition = pim_time_monotonic_sec();
738
739 pim_upstream_update_assert_tracking_desired(up);
740
741 if (new_state == PIM_UPSTREAM_JOINED) {
742 pim_upstream_inherited_olist_decide(pim, up);
743 if (old_state != PIM_UPSTREAM_JOINED) {
744 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
745
746 pim_msdp_up_join_state_changed(pim, up);
747 if (pim_upstream_could_register(up)) {
748 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
749 if (!old_fhr
750 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
751 up->flags)) {
752 pim_upstream_keep_alive_timer_start(
753 up, pim->keep_alive_time);
754 pim_register_join(up);
755 }
756 } else {
757 pim_upstream_send_join(up);
758 join_timer_start(up);
759 }
760 }
761 if (old_state != new_state)
762 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
763 } else {
764 bool old_use_rpt;
765 bool new_use_rpt;
766 bool send_xg_jp = false;
767
768 forward_off(up);
769 /*
770 * RFC 4601 Sec 4.5.7:
771 * JoinDesired(S,G) -> False, set SPTbit to false.
772 */
773 if (!pim_addr_is_any(up->sg.src))
774 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
775
776 if (old_state == PIM_UPSTREAM_JOINED)
777 pim_msdp_up_join_state_changed(pim, up);
778
779 if (old_state != new_state) {
780 old_use_rpt =
781 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
782 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
783 new_use_rpt =
784 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
785 if (new_use_rpt &&
786 (new_use_rpt != old_use_rpt) &&
787 up->parent)
788 /* we have decided to switch from the SPT back
789 * to the RPT which means we need to cancel
790 * any previously sent SGrpt prunes immediately
791 */
792 send_xg_jp = true;
793 }
794
795 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
796 RP.
797 If I am RP for G then send S,G prune to its IIF. */
798 if (pim_upstream_is_sg_rpt(up) && up->parent &&
799 !I_am_RP(pim, up->sg.grp))
800 send_xg_jp = true;
801
802 pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
803
804 if (send_xg_jp) {
805 if (PIM_DEBUG_PIM_TRACE_DETAIL)
806 zlog_debug(
807 "re-join RPT; *,G IIF %s S,G IIF %s ",
808 up->parent->rpf.source_nexthop.interface ?
809 up->parent->rpf.source_nexthop.interface->name
810 : "Unknown",
811 up->rpf.source_nexthop.interface ?
812 up->rpf.source_nexthop.interface->name :
813 "Unknown");
814 pim_jp_agg_single_upstream_send(&up->parent->rpf,
815 up->parent,
816 1 /* (W,G) Join */);
817 }
818 join_timer_stop(up);
819 }
820 }
821
822 int pim_upstream_compare(const struct pim_upstream *up1,
823 const struct pim_upstream *up2)
824 {
825 return pim_sgaddr_cmp(up1->sg, up2->sg);
826 }
827
828 void pim_upstream_fill_static_iif(struct pim_upstream *up,
829 struct interface *incoming)
830 {
831 up->rpf.source_nexthop.interface = incoming;
832
833 /* reset other parameters to matched a connected incoming interface */
834 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
835 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
836 PIM_NET_INADDR_ANY;
837 up->rpf.source_nexthop.mrib_metric_preference =
838 ZEBRA_CONNECT_DISTANCE_DEFAULT;
839 up->rpf.source_nexthop.mrib_route_metric = 0;
840 up->rpf.rpf_addr.family = AF_INET;
841 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
842
843 }
844
845 static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
846 pim_sgaddr *sg,
847 struct interface *incoming,
848 int flags,
849 struct pim_ifchannel *ch)
850 {
851 enum pim_rpf_result rpf_result;
852 struct pim_interface *pim_ifp;
853 struct pim_upstream *up;
854
855 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
856
857 up->pim = pim;
858 up->sg = *sg;
859 snprintfrr(up->sg_str, sizeof(up->sg_str), "%pSG", sg);
860 if (ch)
861 ch->upstream = up;
862
863 rb_pim_upstream_add(&pim->upstream_head, up);
864 /* Set up->upstream_addr as INADDR_ANY, if RP is not
865 * configured and retain the upstream data structure
866 */
867 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
868 sg->grp)) {
869 if (PIM_DEBUG_PIM_TRACE)
870 zlog_debug("%s: Received a (*,G) with no RP configured",
871 __func__);
872 }
873
874 up->parent = pim_upstream_find_parent(pim, up);
875 if (pim_addr_is_any(up->sg.src)) {
876 up->sources = list_new();
877 up->sources->cmp =
878 (int (*)(void *, void *))pim_upstream_compare;
879 } else
880 up->sources = NULL;
881
882 pim_upstream_find_new_children(pim, up);
883 up->flags = flags;
884 up->ref_count = 1;
885 up->t_join_timer = NULL;
886 up->t_ka_timer = NULL;
887 up->t_rs_timer = NULL;
888 up->t_msdp_reg_timer = NULL;
889 up->join_state = PIM_UPSTREAM_NOTJOINED;
890 up->reg_state = PIM_REG_NOINFO;
891 up->state_transition = pim_time_monotonic_sec();
892 up->channel_oil = pim_channel_oil_add(pim, &up->sg, __func__);
893 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
894
895 up->rpf.source_nexthop.interface = NULL;
896 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
897 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
898 PIM_NET_INADDR_ANY;
899 up->rpf.source_nexthop.mrib_metric_preference =
900 router->infinite_assert_metric.metric_preference;
901 up->rpf.source_nexthop.mrib_route_metric =
902 router->infinite_assert_metric.route_metric;
903 up->rpf.rpf_addr.family = AF_INET;
904 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
905
906 up->ifchannels = list_new();
907 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
908
909 if (!pim_addr_is_any(up->sg.src)) {
910 wheel_add_item(pim->upstream_sg_wheel, up);
911
912 /* Inherit the DF role from the parent (*, G) entry for
913 * VxLAN BUM groups
914 */
915 if (up->parent
916 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags)
917 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->parent->flags)) {
918 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
919 if (PIM_DEBUG_VXLAN)
920 zlog_debug(
921 "upstream %s inherited mlag non-df flag from parent",
922 up->sg_str);
923 }
924 }
925
926 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
927 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
928 pim_upstream_fill_static_iif(up, incoming);
929 pim_ifp = up->rpf.source_nexthop.interface->info;
930 assert(pim_ifp);
931 pim_upstream_update_use_rpt(up,
932 false /*update_mroute*/);
933 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
934
935 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
936 pim_upstream_keep_alive_timer_start(
937 up, pim->keep_alive_time);
938 } else if (!pim_addr_is_any(up->upstream_addr)) {
939 pim_upstream_update_use_rpt(up,
940 false /*update_mroute*/);
941 rpf_result = pim_rpf_update(pim, up, NULL, __func__);
942 if (rpf_result == PIM_RPF_FAILURE) {
943 if (PIM_DEBUG_PIM_TRACE)
944 zlog_debug(
945 "%s: Attempting to create upstream(%s), Unable to RPF for source",
946 __func__, up->sg_str);
947 }
948
949 if (up->rpf.source_nexthop.interface) {
950 pim_upstream_mroute_iif_update(up->channel_oil,
951 __func__);
952 }
953 }
954
955 /* send the entry to the MLAG peer */
956 /* XXX - duplicate send is possible here if pim_rpf_update
957 * successfully resolved the nexthop
958 */
959 if (pim_up_mlag_is_local(up)
960 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
961 pim_mlag_up_local_add(pim, up);
962
963 if (PIM_DEBUG_PIM_TRACE) {
964 zlog_debug(
965 "%s: Created Upstream %s upstream_addr %pI4 ref count %d increment",
966 __func__, up->sg_str, &up->upstream_addr,
967 up->ref_count);
968 }
969
970 return up;
971 }
972
973 uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
974 {
975 if (!(pim_up_mlag_is_local(up))
976 && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
977 return router->infinite_assert_metric.route_metric;
978
979 if ((up->rpf.source_nexthop.interface ==
980 up->pim->vxlan.peerlink_rif) &&
981 (up->rpf.source_nexthop.mrib_route_metric <
982 (router->infinite_assert_metric.route_metric -
983 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC)))
984 return up->rpf.source_nexthop.mrib_route_metric +
985 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC;
986
987 return up->rpf.source_nexthop.mrib_route_metric;
988 }
989
990 uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up)
991 {
992 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
993 return router->infinite_assert_metric.route_metric;
994
995 return up->mlag.peer_mrib_metric;
996 }
997
998 struct pim_upstream *pim_upstream_find(struct pim_instance *pim, pim_sgaddr *sg)
999 {
1000 struct pim_upstream lookup;
1001 struct pim_upstream *up = NULL;
1002
1003 lookup.sg = *sg;
1004 up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
1005 return up;
1006 }
1007
1008 struct pim_upstream *pim_upstream_find_or_add(pim_sgaddr *sg,
1009 struct interface *incoming,
1010 int flags, const char *name)
1011 {
1012 struct pim_interface *pim_ifp = incoming->info;
1013
1014 return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
1015 NULL));
1016 }
1017
1018 void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1019 {
1020 /* if a local MLAG reference is being created we need to send the mroute
1021 * to the peer
1022 */
1023 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags) &&
1024 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags)) {
1025 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags);
1026 pim_mlag_up_local_add(up->pim, up);
1027 }
1028
1029 /* when we go from non-FHR to FHR we need to re-eval traffic
1030 * forwarding path
1031 */
1032 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
1033 PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
1034 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1035 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1036 }
1037
1038 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1039 * cause JD to change
1040 */
1041 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags) &&
1042 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags)) {
1043 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up->flags);
1044 pim_upstream_update_join_desired(up->pim, up);
1045 }
1046
1047 up->flags |= flags;
1048 ++up->ref_count;
1049 if (PIM_DEBUG_PIM_TRACE)
1050 zlog_debug("%s(%s): upstream %s ref count %d increment",
1051 __func__, name, up->sg_str, up->ref_count);
1052 }
1053
1054 struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg,
1055 struct interface *incoming, int flags,
1056 const char *name,
1057 struct pim_ifchannel *ch)
1058 {
1059 struct pim_upstream *up = NULL;
1060 int found = 0;
1061
1062 up = pim_upstream_find(pim, sg);
1063 if (up) {
1064 pim_upstream_ref(up, flags, name);
1065 found = 1;
1066 } else {
1067 up = pim_upstream_new(pim, sg, incoming, flags, ch);
1068 }
1069
1070 if (PIM_DEBUG_PIM_TRACE) {
1071 if (up)
1072 zlog_debug("%s(%s): %s, iif %pFX (%s) found: %d: ref_count: %d",
1073 __func__, name,
1074 up->sg_str, &up->rpf.rpf_addr, up->rpf.source_nexthop.interface ?
1075 up->rpf.source_nexthop.interface->name : "Unknown" ,
1076 found, up->ref_count);
1077 else
1078 zlog_debug("%s(%s): (%pSG) failure to create", __func__,
1079 name, sg);
1080 }
1081
1082 return up;
1083 }
1084
1085 /*
1086 * Passed in up must be the upstream for ch. starch is NULL if no
1087 * information
1088 * This function is copied over from
1089 * pim_upstream_evaluate_join_desired_interface but limited to
1090 * parent (*,G)'s includes/joins.
1091 */
1092 int pim_upstream_eval_inherit_if(struct pim_upstream *up,
1093 struct pim_ifchannel *ch,
1094 struct pim_ifchannel *starch)
1095 {
1096 /* if there is an explicit prune for this interface we cannot
1097 * add it to the OIL
1098 */
1099 if (ch) {
1100 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1101 return 0;
1102 }
1103
1104 /* Check if the OIF can be inherited fron the (*,G) entry
1105 */
1106 if (starch) {
1107 if (!pim_macro_ch_lost_assert(starch)
1108 && pim_macro_chisin_joins_or_include(starch))
1109 return 1;
1110 }
1111
1112 return 0;
1113 }
1114
1115 /*
1116 * Passed in up must be the upstream for ch. starch is NULL if no
1117 * information
1118 */
1119 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
1120 struct pim_ifchannel *ch,
1121 struct pim_ifchannel *starch)
1122 {
1123 if (ch) {
1124 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1125 return 0;
1126
1127 if (!pim_macro_ch_lost_assert(ch)
1128 && pim_macro_chisin_joins_or_include(ch))
1129 return 1;
1130 }
1131
1132 /*
1133 * joins (*,G)
1134 */
1135 if (starch) {
1136 /* XXX: check on this with donald
1137 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1138 * upstream flags?
1139 */
1140 #if 0
1141 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1142 return 0;
1143 #endif
1144
1145 if (!pim_macro_ch_lost_assert(starch)
1146 && pim_macro_chisin_joins_or_include(starch))
1147 return 1;
1148 }
1149
1150 return 0;
1151 }
1152
1153 /* Returns true if immediate OIL is empty and is used to evaluate
1154 * JoinDesired. See pim_upstream_evaluate_join_desired.
1155 */
1156 static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
1157 struct pim_upstream *up)
1158 {
1159 struct interface *ifp;
1160 struct pim_ifchannel *ch;
1161
1162 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1163 if (!ifp->info)
1164 continue;
1165
1166 ch = pim_ifchannel_find(ifp, &up->sg);
1167 if (!ch)
1168 continue;
1169
1170 /* If we have even one immediate OIF we can return with
1171 * not-empty
1172 */
1173 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1174 NULL /* starch */))
1175 return false;
1176 } /* scan iface channel list */
1177
1178 /* immediate_oil is empty */
1179 return true;
1180 }
1181
1182
1183 static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1184 {
1185 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1186 }
1187
1188 /*
1189 * bool JoinDesired(*,G) {
1190 * if (immediate_olist(*,G) != NULL)
1191 * return TRUE
1192 * else
1193 * return FALSE
1194 * }
1195 *
1196 * bool JoinDesired(S,G) {
1197 * return( immediate_olist(S,G) != NULL
1198 * OR ( KeepaliveTimer(S,G) is running
1199 * AND inherited_olist(S,G) != NULL ) )
1200 * }
1201 */
1202 bool pim_upstream_evaluate_join_desired(struct pim_instance *pim,
1203 struct pim_upstream *up)
1204 {
1205 bool empty_imm_oil;
1206 bool empty_inh_oil;
1207
1208 empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1209
1210 /* (*,G) */
1211 if (pim_addr_is_any(up->sg.src))
1212 return !empty_imm_oil;
1213
1214 /* (S,G) */
1215 if (!empty_imm_oil)
1216 return true;
1217 empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1218 if (!empty_inh_oil &&
1219 (pim_upstream_is_kat_running(up) ||
1220 pim_upstream_is_msdp_peer_sa(up)))
1221 return true;
1222
1223 return false;
1224 }
1225
1226 /*
1227 See also pim_upstream_evaluate_join_desired() above.
1228 */
1229 void pim_upstream_update_join_desired(struct pim_instance *pim,
1230 struct pim_upstream *up)
1231 {
1232 int was_join_desired; /* boolean */
1233 int is_join_desired; /* boolean */
1234
1235 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1236
1237 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
1238 if (is_join_desired)
1239 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1240 else
1241 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1242
1243 /* switched from false to true */
1244 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1245 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
1246 return;
1247 }
1248
1249 /* switched from true to false */
1250 if (!is_join_desired && was_join_desired) {
1251 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
1252 return;
1253 }
1254 }
1255
1256 /*
1257 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1258 Transitions from Joined State
1259 RPF'(S,G) GenID changes
1260
1261 The upstream (S,G) state machine remains in Joined state. If the
1262 Join Timer is set to expire in more than t_override seconds, reset
1263 it so that it expires after t_override seconds.
1264 */
1265 void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
1266 struct in_addr neigh_addr)
1267 {
1268 struct pim_upstream *up;
1269
1270 /*
1271 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1272 */
1273 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1274 if (PIM_DEBUG_PIM_TRACE) {
1275 char rpf_addr_str[PREFIX_STRLEN];
1276 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
1277 sizeof(rpf_addr_str));
1278 zlog_debug(
1279 "%s: matching neigh=%pI4 against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1280 __func__, &neigh_addr, up->sg_str,
1281 pim->vrf->name,
1282 up->join_state == PIM_UPSTREAM_JOINED,
1283 rpf_addr_str);
1284 }
1285
1286 /* consider only (S,G) upstream in Joined state */
1287 if (up->join_state != PIM_UPSTREAM_JOINED)
1288 continue;
1289
1290 /* match RPF'(S,G)=neigh_addr */
1291 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
1292 continue;
1293
1294 pim_upstream_join_timer_decrease_to_t_override(
1295 "RPF'(S,G) GenID change", up);
1296 }
1297 }
1298
1299
1300 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1301 struct interface *old_rpf_ifp)
1302 {
1303 struct listnode *chnode;
1304 struct listnode *chnextnode;
1305 struct pim_ifchannel *ch;
1306
1307 /* search all ifchannels */
1308 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1309 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1310 if (
1311 /* RPF_interface(S) was NOT I */
1312 (old_rpf_ifp == ch->interface) &&
1313 /* RPF_interface(S) stopped being I */
1314 (ch->upstream->rpf.source_nexthop
1315 .interface) &&
1316 (ch->upstream->rpf.source_nexthop
1317 .interface != ch->interface)) {
1318 assert_action_a5(ch);
1319 }
1320 } /* PIM_IFASSERT_I_AM_LOSER */
1321
1322 pim_ifchannel_update_assert_tracking_desired(ch);
1323 }
1324 }
1325
1326 void pim_upstream_update_could_assert(struct pim_upstream *up)
1327 {
1328 struct listnode *chnode;
1329 struct listnode *chnextnode;
1330 struct pim_ifchannel *ch;
1331
1332 /* scan per-interface (S,G) state */
1333 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1334 pim_ifchannel_update_could_assert(ch);
1335 } /* scan iface channel list */
1336 }
1337
1338 void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1339 {
1340 struct listnode *chnode;
1341 struct listnode *chnextnode;
1342 struct pim_ifchannel *ch;
1343
1344 /* scan per-interface (S,G) state */
1345 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1346 pim_ifchannel_update_my_assert_metric(ch);
1347
1348 } /* scan iface channel list */
1349 }
1350
1351 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1352 {
1353 struct listnode *chnode;
1354 struct listnode *chnextnode;
1355 struct pim_interface *pim_ifp;
1356 struct pim_ifchannel *ch;
1357
1358 /* scan per-interface (S,G) state */
1359 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1360 if (!ch->interface)
1361 continue;
1362 pim_ifp = ch->interface->info;
1363 if (!pim_ifp)
1364 continue;
1365
1366 pim_ifchannel_update_assert_tracking_desired(ch);
1367
1368 } /* scan iface channel list */
1369 }
1370
1371 /* When kat is stopped CouldRegister goes to false so we need to
1372 * transition the (S, G) on FHR to NI state and remove reg tunnel
1373 * from the OIL */
1374 static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1375 struct pim_upstream *up)
1376 {
1377 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1378 return;
1379
1380 if (PIM_DEBUG_PIM_TRACE)
1381 zlog_debug("kat expired on %s; clear fhr reg state",
1382 up->sg_str);
1383
1384 /* stop reg-stop timer */
1385 THREAD_OFF(up->t_rs_timer);
1386 /* remove regiface from the OIL if it is there*/
1387 pim_channel_del_oif(up->channel_oil, pim->regiface,
1388 PIM_OIF_FLAG_PROTO_PIM, __func__);
1389 /* clear the register state */
1390 up->reg_state = PIM_REG_NOINFO;
1391 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1392 }
1393
1394 /* When kat is started CouldRegister can go to true. And if it does we
1395 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1396 * to the OIL */
1397 static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1398 {
1399 if (pim_upstream_could_register(up)) {
1400 if (PIM_DEBUG_PIM_TRACE)
1401 zlog_debug(
1402 "kat started on %s; set fhr reg state to joined",
1403 up->sg_str);
1404
1405 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1406 if (up->reg_state == PIM_REG_NOINFO)
1407 pim_register_join(up);
1408 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1409 }
1410 }
1411
1412 /*
1413 * On an RP, the PMBR value must be cleared when the
1414 * Keepalive Timer expires
1415 * KAT expiry indicates that flow is inactive. If the flow was created or
1416 * maintained by activity now is the time to deref it.
1417 */
1418 struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1419 struct pim_upstream *up)
1420 {
1421 struct pim_instance *pim;
1422
1423 pim = up->channel_oil->pim;
1424
1425 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
1426 /* if the router is a PIM vxlan encapsulator we prevent expiry
1427 * of KAT as the mroute is pre-setup without any traffic
1428 */
1429 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
1430 return up;
1431 }
1432
1433 if (I_am_RP(pim, up->sg.grp)) {
1434 pim_br_clear_pmbr(&up->sg);
1435 /*
1436 * We need to do more here :)
1437 * But this is the start.
1438 */
1439 }
1440
1441 /* source is no longer active - pull the SA from MSDP's cache */
1442 pim_msdp_sa_local_del(pim, &up->sg);
1443
1444 /* JoinDesired can change when KAT is started or stopped */
1445 pim_upstream_update_join_desired(pim, up);
1446
1447 /* if entry was created because of activity we need to deref it */
1448 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1449 pim_upstream_fhr_kat_expiry(pim, up);
1450 if (PIM_DEBUG_PIM_TRACE)
1451 zlog_debug(
1452 "kat expired on %s[%s]; remove stream reference",
1453 up->sg_str, pim->vrf->name);
1454 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1455
1456 /* Return if upstream entry got deleted.*/
1457 if (!pim_upstream_del(pim, up, __func__))
1458 return NULL;
1459 }
1460 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1461 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1462
1463 if (!pim_upstream_del(pim, up, __func__))
1464 return NULL;
1465 }
1466
1467 /* upstream reference would have been added to track the local
1468 * membership if it is LHR. We have to clear it when KAT expires.
1469 * Otherwise would result in stale entry with uncleared ref count.
1470 */
1471 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
1472 struct pim_upstream *parent = up->parent;
1473
1474 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
1475 up = pim_upstream_del(pim, up, __func__);
1476
1477 if (parent) {
1478 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1479 true);
1480 }
1481 }
1482
1483 return up;
1484 }
1485 static int pim_upstream_keep_alive_timer(struct thread *t)
1486 {
1487 struct pim_upstream *up;
1488
1489 up = THREAD_ARG(t);
1490
1491 /* pull the stats and re-check */
1492 if (pim_upstream_sg_running_proc(up))
1493 /* kat was restarted because of new activity */
1494 return 0;
1495
1496 pim_upstream_keep_alive_timer_proc(up);
1497 return 0;
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 int 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 return 1;
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 int 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 0;
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 0;
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 0;
1761 }
1762 pim_null_register_send(up);
1763 break;
1764 case PIM_REG_NOINFO:
1765 break;
1766 }
1767
1768 return 0;
1769 }
1770
1771 void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1772 int null_register)
1773 {
1774 uint32_t time;
1775
1776 THREAD_OFF(up->t_rs_timer);
1777
1778 if (!null_register) {
1779 uint32_t lower = (0.5 * router->register_suppress_time);
1780 uint32_t upper = (1.5 * router->register_suppress_time);
1781 time = lower + (frr_weak_random() % (upper - lower + 1));
1782 /* Make sure we don't wrap around */
1783 if (time >= router->register_probe_time)
1784 time -= router->register_probe_time;
1785 else
1786 time = 0;
1787 } else
1788 time = router->register_probe_time;
1789
1790 if (PIM_DEBUG_PIM_TRACE) {
1791 zlog_debug(
1792 "%s: (S,G)=%s Starting upstream register stop timer %d",
1793 __func__, up->sg_str, time);
1794 }
1795 thread_add_timer(router->master, pim_upstream_register_stop_timer, up,
1796 time, &up->t_rs_timer);
1797 }
1798
1799 int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1800 struct pim_upstream *up)
1801 {
1802 struct interface *ifp;
1803 struct pim_ifchannel *ch, *starch;
1804 struct pim_upstream *starup = up->parent;
1805 int output_intf = 0;
1806
1807 if (!up->rpf.source_nexthop.interface)
1808 if (PIM_DEBUG_PIM_TRACE)
1809 zlog_debug("%s: up %s RPF is not present", __func__,
1810 up->sg_str);
1811
1812 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1813 struct pim_interface *pim_ifp;
1814 if (!ifp->info)
1815 continue;
1816
1817 ch = pim_ifchannel_find(ifp, &up->sg);
1818
1819 if (starup)
1820 starch = pim_ifchannel_find(ifp, &starup->sg);
1821 else
1822 starch = NULL;
1823
1824 if (!ch && !starch)
1825 continue;
1826
1827 pim_ifp = ifp->info;
1828 if (PIM_I_am_DualActive(pim_ifp)
1829 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
1830 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
1831 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
1832 continue;
1833 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1834 starch)) {
1835 int flag = 0;
1836
1837 if (!ch)
1838 flag = PIM_OIF_FLAG_PROTO_STAR;
1839 else {
1840 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1841 flag = PIM_OIF_FLAG_PROTO_IGMP;
1842 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1843 flag |= PIM_OIF_FLAG_PROTO_PIM;
1844 if (starch)
1845 flag |= PIM_OIF_FLAG_PROTO_STAR;
1846 }
1847
1848 pim_channel_add_oif(up->channel_oil, ifp, flag,
1849 __func__);
1850 output_intf++;
1851 }
1852 }
1853
1854 return output_intf;
1855 }
1856
1857 /*
1858 * For a given upstream, determine the inherited_olist
1859 * and apply it.
1860 *
1861 * inherited_olist(S,G,rpt) =
1862 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1863 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1864 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1865 *
1866 * inherited_olist(S,G) =
1867 * inherited_olist(S,G,rpt) (+)
1868 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1869 *
1870 * return 1 if there are any output interfaces
1871 * return 0 if there are not any output interfaces
1872 */
1873 int pim_upstream_inherited_olist(struct pim_instance *pim,
1874 struct pim_upstream *up)
1875 {
1876 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
1877
1878 /*
1879 * If we have output_intf switch state to Join and work like normal
1880 * If we don't have an output_intf that means we are probably a
1881 * switch on a stick so turn on forwarding to just accept the
1882 * incoming packets so we don't bother the other stuff!
1883 */
1884 pim_upstream_update_join_desired(pim, up);
1885
1886 if (!output_intf)
1887 forward_on(up);
1888
1889 return output_intf;
1890 }
1891
1892 int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
1893 {
1894 return pim_channel_oil_empty(up->channel_oil);
1895 }
1896
1897 /*
1898 * When we have a new neighbor,
1899 * find upstreams that don't have their rpf_addr
1900 * set and see if the new neighbor allows
1901 * the join to be sent
1902 */
1903 void pim_upstream_find_new_rpf(struct pim_instance *pim)
1904 {
1905 struct pim_upstream *up;
1906 struct pim_rpf old;
1907 enum pim_rpf_result rpf_result;
1908
1909 /*
1910 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1911 */
1912 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1913 if (pim_addr_is_any(up->upstream_addr)) {
1914 if (PIM_DEBUG_PIM_TRACE)
1915 zlog_debug(
1916 "%s: RP not configured for Upstream %s",
1917 __func__, up->sg_str);
1918 continue;
1919 }
1920
1921 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1922 if (PIM_DEBUG_PIM_TRACE)
1923 zlog_debug(
1924 "%s: Upstream %s without a path to send join, checking",
1925 __func__, up->sg_str);
1926 old.source_nexthop.interface =
1927 up->rpf.source_nexthop.interface;
1928 rpf_result = pim_rpf_update(pim, up, &old, __func__);
1929 if (rpf_result == PIM_RPF_CHANGED ||
1930 (rpf_result == PIM_RPF_FAILURE &&
1931 old.source_nexthop.interface))
1932 pim_zebra_upstream_rpf_changed(pim, up, &old);
1933 /* update kernel multicast forwarding cache (MFC) */
1934 pim_upstream_mroute_iif_update(up->channel_oil,
1935 __func__);
1936 }
1937 }
1938 pim_zebra_update_all_interfaces(pim);
1939 }
1940
1941 unsigned int pim_upstream_hash_key(const void *arg)
1942 {
1943 const struct pim_upstream *up = arg;
1944
1945 return pim_sgaddr_hash(up->sg, 0);
1946 }
1947
1948 void pim_upstream_terminate(struct pim_instance *pim)
1949 {
1950 struct pim_upstream *up;
1951
1952 while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
1953 pim_upstream_del(pim, up, __func__);
1954 }
1955
1956 rb_pim_upstream_fini(&pim->upstream_head);
1957
1958 if (pim->upstream_sg_wheel)
1959 wheel_delete(pim->upstream_sg_wheel);
1960 pim->upstream_sg_wheel = NULL;
1961 }
1962
1963 bool pim_upstream_equal(const void *arg1, const void *arg2)
1964 {
1965 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1966 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1967
1968 return !pim_sgaddr_cmp(up1->sg, up2->sg);
1969 }
1970
1971 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1972 * the cases where kat has to be restarted on rxing traffic -
1973 *
1974 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1975 * set KeepaliveTimer(S,G) to Keepalive_Period
1976 * # Note: a register state transition or UpstreamJPState(S,G)
1977 * # transition may happen as a result of restarting
1978 * # KeepaliveTimer, and must be dealt with here.
1979 * }
1980 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1981 * inherited_olist(S,G) != NULL ) {
1982 * set KeepaliveTimer(S,G) to Keepalive_Period
1983 * }
1984 */
1985 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1986 {
1987 struct channel_oil *c_oil = up->channel_oil;
1988 struct interface *ifp = up->rpf.source_nexthop.interface;
1989 struct pim_interface *pim_ifp;
1990
1991 /* "iif == RPF_interface(S)" check is not easy to do as the info
1992 * we get from the kernel/ASIC is really a "lookup/key hit".
1993 * So we will do an approximate check here to avoid starting KAT
1994 * because of (S,G,rpt) forwarding on a non-LHR.
1995 */
1996 if (!ifp)
1997 return false;
1998
1999 pim_ifp = ifp->info;
2000 if (pim_ifp->mroute_vif_index != c_oil->oil.mfcc_parent)
2001 return false;
2002
2003 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
2004 up->sg.src)) {
2005 return true;
2006 }
2007
2008 if ((up->join_state == PIM_UPSTREAM_JOINED)
2009 && !pim_upstream_empty_inherited_olist(up)) {
2010 return true;
2011 }
2012
2013 return false;
2014 }
2015
2016 static bool pim_upstream_sg_running_proc(struct pim_upstream *up)
2017 {
2018 bool rv = false;
2019 struct pim_instance *pim = up->pim;
2020
2021 if (!up->channel_oil->installed)
2022 return rv;
2023
2024 pim_mroute_update_counters(up->channel_oil);
2025
2026 // Have we seen packets?
2027 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
2028 && (up->channel_oil->cc.lastused / 100 > 30)) {
2029 if (PIM_DEBUG_PIM_TRACE) {
2030 zlog_debug(
2031 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2032 __func__, up->sg_str, pim->vrf->name,
2033 up->channel_oil->cc.oldpktcnt,
2034 up->channel_oil->cc.pktcnt,
2035 up->channel_oil->cc.lastused / 100);
2036 }
2037 return rv;
2038 }
2039
2040 if (pim_upstream_kat_start_ok(up)) {
2041 /* Add a source reference to the stream if
2042 * one doesn't already exist */
2043 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
2044 if (PIM_DEBUG_PIM_TRACE)
2045 zlog_debug(
2046 "source reference created on kat restart %s[%s]",
2047 up->sg_str, pim->vrf->name);
2048
2049 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
2050 __func__);
2051 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
2052 pim_upstream_fhr_kat_start(up);
2053 }
2054 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2055 rv = true;
2056 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
2057 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2058 rv = true;
2059 }
2060
2061 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
2062 (up->rpf.source_nexthop.interface)) {
2063 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
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_IGMP, __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_IGMP, __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_IGMP,
2171 __func__);
2172 else
2173 pim_channel_del_oif(up->channel_oil, pim->regiface,
2174 PIM_OIF_FLAG_PROTO_IGMP, __func__);
2175 }
2176 }
2177
2178 void pim_upstream_init(struct pim_instance *pim)
2179 {
2180 char name[64];
2181
2182 snprintf(name, sizeof(name), "PIM %s Timer Wheel", pim->vrf->name);
2183 pim->upstream_sg_wheel =
2184 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
2185 pim_upstream_sg_running, name);
2186
2187 rb_pim_upstream_init(&pim->upstream_head);
2188 }